1 /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. 2 * 3 * This program is free software; you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License version 2 and 5 * only version 2 as published by the Free Software Foundation. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 */ 12 13 #include "dpu_hwio.h" 14 #include "dpu_hw_catalog.h" 15 #include "dpu_hw_vbif.h" 16 #include "dpu_dbg.h" 17 18 #define VBIF_VERSION 0x0000 19 #define VBIF_CLK_FORCE_CTRL0 0x0008 20 #define VBIF_CLK_FORCE_CTRL1 0x000C 21 #define VBIF_QOS_REMAP_00 0x0020 22 #define VBIF_QOS_REMAP_01 0x0024 23 #define VBIF_QOS_REMAP_10 0x0028 24 #define VBIF_QOS_REMAP_11 0x002C 25 #define VBIF_WRITE_GATHER_EN 0x00AC 26 #define VBIF_IN_RD_LIM_CONF0 0x00B0 27 #define VBIF_IN_RD_LIM_CONF1 0x00B4 28 #define VBIF_IN_RD_LIM_CONF2 0x00B8 29 #define VBIF_IN_WR_LIM_CONF0 0x00C0 30 #define VBIF_IN_WR_LIM_CONF1 0x00C4 31 #define VBIF_IN_WR_LIM_CONF2 0x00C8 32 #define VBIF_OUT_RD_LIM_CONF0 0x00D0 33 #define VBIF_OUT_WR_LIM_CONF0 0x00D4 34 #define VBIF_OUT_AXI_AMEMTYPE_CONF0 0x0160 35 #define VBIF_OUT_AXI_AMEMTYPE_CONF1 0x0164 36 #define VBIF_XIN_PND_ERR 0x0190 37 #define VBIF_XIN_SRC_ERR 0x0194 38 #define VBIF_XIN_CLR_ERR 0x019C 39 #define VBIF_XIN_HALT_CTRL0 0x0200 40 #define VBIF_XIN_HALT_CTRL1 0x0204 41 #define VBIF_XINL_QOS_RP_REMAP_000 0x0550 42 #define VBIF_XINL_QOS_LVL_REMAP_000 0x0590 43 44 static void dpu_hw_clear_errors(struct dpu_hw_vbif *vbif, 45 u32 *pnd_errors, u32 *src_errors) 46 { 47 struct dpu_hw_blk_reg_map *c; 48 u32 pnd, src; 49 50 if (!vbif) 51 return; 52 c = &vbif->hw; 53 pnd = DPU_REG_READ(c, VBIF_XIN_PND_ERR); 54 src = DPU_REG_READ(c, VBIF_XIN_SRC_ERR); 55 56 if (pnd_errors) 57 *pnd_errors = pnd; 58 if (src_errors) 59 *src_errors = src; 60 61 DPU_REG_WRITE(c, VBIF_XIN_CLR_ERR, pnd | src); 62 } 63 64 static void dpu_hw_set_mem_type(struct dpu_hw_vbif *vbif, 65 u32 xin_id, u32 value) 66 { 67 struct dpu_hw_blk_reg_map *c; 68 u32 reg_off; 69 u32 bit_off; 70 u32 reg_val; 71 72 /* 73 * Assume 4 bits per bit field, 8 fields per 32-bit register so 74 * 16 bit fields maximum across two registers 75 */ 76 if (!vbif || xin_id >= MAX_XIN_COUNT || xin_id >= 16) 77 return; 78 79 c = &vbif->hw; 80 81 if (xin_id >= 8) { 82 xin_id -= 8; 83 reg_off = VBIF_OUT_AXI_AMEMTYPE_CONF1; 84 } else { 85 reg_off = VBIF_OUT_AXI_AMEMTYPE_CONF0; 86 } 87 bit_off = (xin_id & 0x7) * 4; 88 reg_val = DPU_REG_READ(c, reg_off); 89 reg_val &= ~(0x7 << bit_off); 90 reg_val |= (value & 0x7) << bit_off; 91 DPU_REG_WRITE(c, reg_off, reg_val); 92 } 93 94 static void dpu_hw_set_limit_conf(struct dpu_hw_vbif *vbif, 95 u32 xin_id, bool rd, u32 limit) 96 { 97 struct dpu_hw_blk_reg_map *c = &vbif->hw; 98 u32 reg_val; 99 u32 reg_off; 100 u32 bit_off; 101 102 if (rd) 103 reg_off = VBIF_IN_RD_LIM_CONF0; 104 else 105 reg_off = VBIF_IN_WR_LIM_CONF0; 106 107 reg_off += (xin_id / 4) * 4; 108 bit_off = (xin_id % 4) * 8; 109 reg_val = DPU_REG_READ(c, reg_off); 110 reg_val &= ~(0xFF << bit_off); 111 reg_val |= (limit) << bit_off; 112 DPU_REG_WRITE(c, reg_off, reg_val); 113 } 114 115 static u32 dpu_hw_get_limit_conf(struct dpu_hw_vbif *vbif, 116 u32 xin_id, bool rd) 117 { 118 struct dpu_hw_blk_reg_map *c = &vbif->hw; 119 u32 reg_val; 120 u32 reg_off; 121 u32 bit_off; 122 u32 limit; 123 124 if (rd) 125 reg_off = VBIF_IN_RD_LIM_CONF0; 126 else 127 reg_off = VBIF_IN_WR_LIM_CONF0; 128 129 reg_off += (xin_id / 4) * 4; 130 bit_off = (xin_id % 4) * 8; 131 reg_val = DPU_REG_READ(c, reg_off); 132 limit = (reg_val >> bit_off) & 0xFF; 133 134 return limit; 135 } 136 137 static void dpu_hw_set_halt_ctrl(struct dpu_hw_vbif *vbif, 138 u32 xin_id, bool enable) 139 { 140 struct dpu_hw_blk_reg_map *c = &vbif->hw; 141 u32 reg_val; 142 143 reg_val = DPU_REG_READ(c, VBIF_XIN_HALT_CTRL0); 144 145 if (enable) 146 reg_val |= BIT(xin_id); 147 else 148 reg_val &= ~BIT(xin_id); 149 150 DPU_REG_WRITE(c, VBIF_XIN_HALT_CTRL0, reg_val); 151 } 152 153 static bool dpu_hw_get_halt_ctrl(struct dpu_hw_vbif *vbif, 154 u32 xin_id) 155 { 156 struct dpu_hw_blk_reg_map *c = &vbif->hw; 157 u32 reg_val; 158 159 reg_val = DPU_REG_READ(c, VBIF_XIN_HALT_CTRL1); 160 161 return (reg_val & BIT(xin_id)) ? true : false; 162 } 163 164 static void dpu_hw_set_qos_remap(struct dpu_hw_vbif *vbif, 165 u32 xin_id, u32 level, u32 remap_level) 166 { 167 struct dpu_hw_blk_reg_map *c; 168 u32 reg_val, reg_val_lvl, mask, reg_high, reg_shift; 169 170 if (!vbif) 171 return; 172 173 c = &vbif->hw; 174 175 reg_high = ((xin_id & 0x8) >> 3) * 4 + (level * 8); 176 reg_shift = (xin_id & 0x7) * 4; 177 178 reg_val = DPU_REG_READ(c, VBIF_XINL_QOS_RP_REMAP_000 + reg_high); 179 reg_val_lvl = DPU_REG_READ(c, VBIF_XINL_QOS_LVL_REMAP_000 + reg_high); 180 181 mask = 0x7 << reg_shift; 182 183 reg_val &= ~mask; 184 reg_val |= (remap_level << reg_shift) & mask; 185 186 reg_val_lvl &= ~mask; 187 reg_val_lvl |= (remap_level << reg_shift) & mask; 188 189 DPU_REG_WRITE(c, VBIF_XINL_QOS_RP_REMAP_000 + reg_high, reg_val); 190 DPU_REG_WRITE(c, VBIF_XINL_QOS_LVL_REMAP_000 + reg_high, reg_val_lvl); 191 } 192 193 static void dpu_hw_set_write_gather_en(struct dpu_hw_vbif *vbif, u32 xin_id) 194 { 195 struct dpu_hw_blk_reg_map *c; 196 u32 reg_val; 197 198 if (!vbif || xin_id >= MAX_XIN_COUNT) 199 return; 200 201 c = &vbif->hw; 202 203 reg_val = DPU_REG_READ(c, VBIF_WRITE_GATHER_EN); 204 reg_val |= BIT(xin_id); 205 DPU_REG_WRITE(c, VBIF_WRITE_GATHER_EN, reg_val); 206 } 207 208 static void _setup_vbif_ops(struct dpu_hw_vbif_ops *ops, 209 unsigned long cap) 210 { 211 ops->set_limit_conf = dpu_hw_set_limit_conf; 212 ops->get_limit_conf = dpu_hw_get_limit_conf; 213 ops->set_halt_ctrl = dpu_hw_set_halt_ctrl; 214 ops->get_halt_ctrl = dpu_hw_get_halt_ctrl; 215 if (test_bit(DPU_VBIF_QOS_REMAP, &cap)) 216 ops->set_qos_remap = dpu_hw_set_qos_remap; 217 ops->set_mem_type = dpu_hw_set_mem_type; 218 ops->clear_errors = dpu_hw_clear_errors; 219 ops->set_write_gather_en = dpu_hw_set_write_gather_en; 220 } 221 222 static const struct dpu_vbif_cfg *_top_offset(enum dpu_vbif vbif, 223 const struct dpu_mdss_cfg *m, 224 void __iomem *addr, 225 struct dpu_hw_blk_reg_map *b) 226 { 227 int i; 228 229 for (i = 0; i < m->vbif_count; i++) { 230 if (vbif == m->vbif[i].id) { 231 b->base_off = addr; 232 b->blk_off = m->vbif[i].base; 233 b->length = m->vbif[i].len; 234 b->hwversion = m->hwversion; 235 b->log_mask = DPU_DBG_MASK_VBIF; 236 return &m->vbif[i]; 237 } 238 } 239 240 return ERR_PTR(-EINVAL); 241 } 242 243 struct dpu_hw_vbif *dpu_hw_vbif_init(enum dpu_vbif idx, 244 void __iomem *addr, 245 const struct dpu_mdss_cfg *m) 246 { 247 struct dpu_hw_vbif *c; 248 const struct dpu_vbif_cfg *cfg; 249 250 c = kzalloc(sizeof(*c), GFP_KERNEL); 251 if (!c) 252 return ERR_PTR(-ENOMEM); 253 254 cfg = _top_offset(idx, m, addr, &c->hw); 255 if (IS_ERR_OR_NULL(cfg)) { 256 kfree(c); 257 return ERR_PTR(-EINVAL); 258 } 259 260 /* 261 * Assign ops 262 */ 263 c->idx = idx; 264 c->cap = cfg; 265 _setup_vbif_ops(&c->ops, c->cap->features); 266 267 /* no need to register sub-range in dpu dbg, dump entire vbif io base */ 268 269 return c; 270 } 271 272 void dpu_hw_vbif_destroy(struct dpu_hw_vbif *vbif) 273 { 274 kfree(vbif); 275 } 276