summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/msm/sde/sde_hw_vbif.c
blob: 048ec47d7c721a0e31d6e9c8a213c4476290d763 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include "sde_hwio.h"
#include "sde_hw_catalog.h"
#include "sde_hw_vbif.h"
#include "sde_dbg.h"

#define VBIF_VERSION			0x0000
#define VBIF_CLK_FORCE_CTRL0		0x0008
#define VBIF_CLK_FORCE_CTRL1		0x000C
#define VBIF_QOS_REMAP_00		0x0020
#define VBIF_QOS_REMAP_01		0x0024
#define VBIF_QOS_REMAP_10		0x0028
#define VBIF_QOS_REMAP_11		0x002C
#define VBIF_WRITE_GATHTER_EN		0x00AC
#define VBIF_IN_RD_LIM_CONF0		0x00B0
#define VBIF_IN_RD_LIM_CONF1		0x00B4
#define VBIF_IN_RD_LIM_CONF2		0x00B8
#define VBIF_IN_WR_LIM_CONF0		0x00C0
#define VBIF_IN_WR_LIM_CONF1		0x00C4
#define VBIF_IN_WR_LIM_CONF2		0x00C8
#define VBIF_OUT_RD_LIM_CONF0		0x00D0
#define VBIF_OUT_WR_LIM_CONF0		0x00D4
#define VBIF_XIN_HALT_CTRL0		0x0200
#define VBIF_XIN_HALT_CTRL1		0x0204

static void sde_hw_set_limit_conf(struct sde_hw_vbif *vbif,
		u32 xin_id, bool rd, u32 limit)
{
	struct sde_hw_blk_reg_map *c = &vbif->hw;
	u32 reg_val;
	u32 reg_off;
	u32 bit_off;

	if (rd)
		reg_off = VBIF_IN_RD_LIM_CONF0;
	else
		reg_off = VBIF_IN_WR_LIM_CONF0;

	reg_off += (xin_id / 4) * 4;
	bit_off = (xin_id % 4) * 8;
	reg_val = SDE_REG_READ(c, reg_off);
	reg_val &= ~(0xFF << bit_off);
	reg_val |= (limit) << bit_off;
	SDE_REG_WRITE(c, reg_off, reg_val);
}

static u32 sde_hw_get_limit_conf(struct sde_hw_vbif *vbif,
		u32 xin_id, bool rd)
{
	struct sde_hw_blk_reg_map *c = &vbif->hw;
	u32 reg_val;
	u32 reg_off;
	u32 bit_off;
	u32 limit;

	if (rd)
		reg_off = VBIF_IN_RD_LIM_CONF0;
	else
		reg_off = VBIF_IN_WR_LIM_CONF0;

	reg_off += (xin_id / 4) * 4;
	bit_off = (xin_id % 4) * 8;
	reg_val = SDE_REG_READ(c, reg_off);
	limit = (reg_val >> bit_off) & 0xFF;

	return limit;
}

static void sde_hw_set_halt_ctrl(struct sde_hw_vbif *vbif,
		u32 xin_id, bool enable)
{
	struct sde_hw_blk_reg_map *c = &vbif->hw;
	u32 reg_val;

	reg_val = SDE_REG_READ(c, VBIF_XIN_HALT_CTRL0);

	if (enable)
		reg_val |= BIT(xin_id);
	else
		reg_val &= ~BIT(xin_id);

	SDE_REG_WRITE(c, VBIF_XIN_HALT_CTRL0, reg_val);
}

static bool sde_hw_get_halt_ctrl(struct sde_hw_vbif *vbif,
		u32 xin_id)
{
	struct sde_hw_blk_reg_map *c = &vbif->hw;
	u32 reg_val;

	reg_val = SDE_REG_READ(c, VBIF_XIN_HALT_CTRL1);

	return (reg_val & BIT(xin_id)) ? true : false;
}

static void _setup_vbif_ops(struct sde_hw_vbif_ops *ops,
		unsigned long cap)
{
	ops->set_limit_conf = sde_hw_set_limit_conf;
	ops->get_limit_conf = sde_hw_get_limit_conf;
	ops->set_halt_ctrl = sde_hw_set_halt_ctrl;
	ops->get_halt_ctrl = sde_hw_get_halt_ctrl;
}

static const struct sde_vbif_cfg *_top_offset(enum sde_vbif vbif,
		const struct sde_mdss_cfg *m,
		void __iomem *addr,
		struct sde_hw_blk_reg_map *b)
{
	int i;

	for (i = 0; i < m->vbif_count; i++) {
		if (vbif == m->vbif[i].id) {
			b->base_off = addr;
			b->blk_off = m->vbif[i].base;
			b->length = m->vbif[i].len;
			b->hwversion = m->hwversion;
			b->log_mask = SDE_DBG_MASK_VBIF;
			return &m->vbif[i];
		}
	}

	return ERR_PTR(-EINVAL);
}

struct sde_hw_vbif *sde_hw_vbif_init(enum sde_vbif idx,
		void __iomem *addr,
		const struct sde_mdss_cfg *m)
{
	struct sde_hw_vbif *c;
	const struct sde_vbif_cfg *cfg;

	c = kzalloc(sizeof(*c), GFP_KERNEL);
	if (!c)
		return ERR_PTR(-ENOMEM);

	cfg = _top_offset(idx, m, addr, &c->hw);
	if (IS_ERR_OR_NULL(cfg)) {
		kfree(c);
		return ERR_PTR(-EINVAL);
	}

	/*
	 * Assign ops
	 */
	c->idx = idx;
	c->cap = cfg;
	_setup_vbif_ops(&c->ops, c->cap->features);

	/* no need to register sub-range in sde dbg, dump entire vbif io base */

	return c;
}

void sde_hw_vbif_destroy(struct sde_hw_vbif *vbif)
{
	kfree(vbif);
}