Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 288 lines 7.1 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright 2024 NXP 4 */ 5 6#include <linux/bitfield.h> 7#include <linux/bits.h> 8#include <linux/component.h> 9#include <linux/mod_devicetable.h> 10#include <linux/module.h> 11#include <linux/platform_device.h> 12#include <linux/regmap.h> 13 14#include "dc-drv.h" 15#include "dc-pe.h" 16 17#define PIXENGCFG_STATIC 0x8 18#define DIV_MASK GENMASK(23, 16) 19#define DIV(x) FIELD_PREP(DIV_MASK, (x)) 20#define DIV_RESET 0x80 21#define SYNC_MODE BIT(8) 22#define SINGLE 0 23#define POWERDOWN BIT(4) 24 25#define PIXENGCFG_DYNAMIC 0xc 26 27#define PIXENGCFG_TRIGGER 0x14 28#define SYNC_TRIGGER BIT(0) 29 30#define STATICCONTROL 0x8 31#define PERFCOUNTMODE BIT(12) 32#define KICK_MODE BIT(8) 33#define EXTERNAL BIT(8) 34 35#define CONTROL 0xc 36#define GAMMAAPPLYENABLE BIT(0) 37 38static const struct dc_subdev_info dc_ed_info[] = { 39 { .reg_start = 0x56180980, .id = 0, }, 40 { .reg_start = 0x56180a00, .id = 1, }, 41 { .reg_start = 0x561809c0, .id = 4, }, 42 { .reg_start = 0x56180a40, .id = 5, }, 43}; 44 45static const struct regmap_range dc_ed_pec_regmap_write_ranges[] = { 46 regmap_reg_range(PIXENGCFG_STATIC, PIXENGCFG_STATIC), 47 regmap_reg_range(PIXENGCFG_DYNAMIC, PIXENGCFG_DYNAMIC), 48 regmap_reg_range(PIXENGCFG_TRIGGER, PIXENGCFG_TRIGGER), 49}; 50 51static const struct regmap_access_table dc_ed_pec_regmap_write_table = { 52 .yes_ranges = dc_ed_pec_regmap_write_ranges, 53 .n_yes_ranges = ARRAY_SIZE(dc_ed_pec_regmap_write_ranges), 54}; 55 56static const struct regmap_range dc_ed_pec_regmap_read_ranges[] = { 57 regmap_reg_range(PIXENGCFG_STATIC, PIXENGCFG_STATIC), 58 regmap_reg_range(PIXENGCFG_DYNAMIC, PIXENGCFG_DYNAMIC), 59}; 60 61static const struct regmap_access_table dc_ed_pec_regmap_read_table = { 62 .yes_ranges = dc_ed_pec_regmap_read_ranges, 63 .n_yes_ranges = ARRAY_SIZE(dc_ed_pec_regmap_read_ranges), 64}; 65 66static const struct regmap_range dc_ed_pec_regmap_volatile_ranges[] = { 67 regmap_reg_range(PIXENGCFG_TRIGGER, PIXENGCFG_TRIGGER), 68}; 69 70static const struct regmap_access_table dc_ed_pec_regmap_volatile_table = { 71 .yes_ranges = dc_ed_pec_regmap_volatile_ranges, 72 .n_yes_ranges = ARRAY_SIZE(dc_ed_pec_regmap_volatile_ranges), 73}; 74 75static const struct regmap_config dc_ed_pec_regmap_config = { 76 .name = "pec", 77 .reg_bits = 32, 78 .reg_stride = 4, 79 .val_bits = 32, 80 .fast_io = true, 81 .wr_table = &dc_ed_pec_regmap_write_table, 82 .rd_table = &dc_ed_pec_regmap_read_table, 83 .volatile_table = &dc_ed_pec_regmap_volatile_table, 84 .max_register = PIXENGCFG_TRIGGER, 85}; 86 87static const struct regmap_range dc_ed_regmap_ranges[] = { 88 regmap_reg_range(STATICCONTROL, STATICCONTROL), 89 regmap_reg_range(CONTROL, CONTROL), 90}; 91 92static const struct regmap_access_table dc_ed_regmap_access_table = { 93 .yes_ranges = dc_ed_regmap_ranges, 94 .n_yes_ranges = ARRAY_SIZE(dc_ed_regmap_ranges), 95}; 96 97static const struct regmap_config dc_ed_cfg_regmap_config = { 98 .name = "cfg", 99 .reg_bits = 32, 100 .reg_stride = 4, 101 .val_bits = 32, 102 .fast_io = true, 103 .wr_table = &dc_ed_regmap_access_table, 104 .rd_table = &dc_ed_regmap_access_table, 105 .max_register = CONTROL, 106}; 107 108static const enum dc_link_id src_sels[] = { 109 LINK_ID_NONE, 110 LINK_ID_CONSTFRAME0, 111 LINK_ID_CONSTFRAME1, 112 LINK_ID_CONSTFRAME4, 113 LINK_ID_CONSTFRAME5, 114 LINK_ID_LAYERBLEND3, 115 LINK_ID_LAYERBLEND2, 116 LINK_ID_LAYERBLEND1, 117 LINK_ID_LAYERBLEND0, 118}; 119 120static inline void dc_ed_pec_enable_shden(struct dc_ed *ed) 121{ 122 regmap_write_bits(ed->reg_pec, PIXENGCFG_STATIC, SHDEN, SHDEN); 123} 124 125static inline void dc_ed_pec_poweron(struct dc_ed *ed) 126{ 127 regmap_write_bits(ed->reg_pec, PIXENGCFG_STATIC, POWERDOWN, 0); 128} 129 130static inline void dc_ed_pec_sync_mode_single(struct dc_ed *ed) 131{ 132 regmap_write_bits(ed->reg_pec, PIXENGCFG_STATIC, SYNC_MODE, SINGLE); 133} 134 135static inline void dc_ed_pec_div_reset(struct dc_ed *ed) 136{ 137 regmap_write_bits(ed->reg_pec, PIXENGCFG_STATIC, DIV_MASK, 138 DIV(DIV_RESET)); 139} 140 141void dc_ed_pec_src_sel(struct dc_ed *ed, enum dc_link_id src) 142{ 143 int i; 144 145 for (i = 0; i < ARRAY_SIZE(src_sels); i++) { 146 if (src_sels[i] == src) { 147 regmap_write(ed->reg_pec, PIXENGCFG_DYNAMIC, src); 148 return; 149 } 150 } 151} 152 153void dc_ed_pec_sync_trigger(struct dc_ed *ed) 154{ 155 regmap_write(ed->reg_pec, PIXENGCFG_TRIGGER, SYNC_TRIGGER); 156} 157 158static inline void dc_ed_enable_shden(struct dc_ed *ed) 159{ 160 regmap_write_bits(ed->reg_cfg, STATICCONTROL, SHDEN, SHDEN); 161} 162 163static inline void dc_ed_kick_mode_external(struct dc_ed *ed) 164{ 165 regmap_write_bits(ed->reg_cfg, STATICCONTROL, KICK_MODE, EXTERNAL); 166} 167 168static inline void dc_ed_disable_perfcountmode(struct dc_ed *ed) 169{ 170 regmap_write_bits(ed->reg_cfg, STATICCONTROL, PERFCOUNTMODE, 0); 171} 172 173static inline void dc_ed_disable_gamma_apply(struct dc_ed *ed) 174{ 175 regmap_write_bits(ed->reg_cfg, CONTROL, GAMMAAPPLYENABLE, 0); 176} 177 178void dc_ed_init(struct dc_ed *ed) 179{ 180 dc_ed_pec_src_sel(ed, LINK_ID_NONE); 181 dc_ed_pec_enable_shden(ed); 182 dc_ed_pec_poweron(ed); 183 dc_ed_pec_sync_mode_single(ed); 184 dc_ed_pec_div_reset(ed); 185 dc_ed_enable_shden(ed); 186 dc_ed_disable_perfcountmode(ed); 187 dc_ed_kick_mode_external(ed); 188 dc_ed_disable_gamma_apply(ed); 189} 190 191static int dc_ed_bind(struct device *dev, struct device *master, void *data) 192{ 193 struct platform_device *pdev = to_platform_device(dev); 194 struct dc_drm_device *dc_drm = data; 195 struct resource *res_pec; 196 void __iomem *base_pec; 197 void __iomem *base_cfg; 198 struct dc_ed *ed; 199 int id; 200 201 ed = devm_kzalloc(dev, sizeof(*ed), GFP_KERNEL); 202 if (!ed) 203 return -ENOMEM; 204 205 base_pec = devm_platform_get_and_ioremap_resource(pdev, 0, &res_pec); 206 if (IS_ERR(base_pec)) 207 return PTR_ERR(base_pec); 208 209 base_cfg = devm_platform_ioremap_resource_byname(pdev, "cfg"); 210 if (IS_ERR(base_cfg)) 211 return PTR_ERR(base_cfg); 212 213 ed->reg_pec = devm_regmap_init_mmio(dev, base_pec, 214 &dc_ed_pec_regmap_config); 215 if (IS_ERR(ed->reg_pec)) 216 return PTR_ERR(ed->reg_pec); 217 218 ed->reg_cfg = devm_regmap_init_mmio(dev, base_cfg, 219 &dc_ed_cfg_regmap_config); 220 if (IS_ERR(ed->reg_cfg)) 221 return PTR_ERR(ed->reg_cfg); 222 223 ed->irq_shdload = platform_get_irq_byname(pdev, "shdload"); 224 if (ed->irq_shdload < 0) 225 return ed->irq_shdload; 226 227 ed->dev = dev; 228 229 id = dc_subdev_get_id(dc_ed_info, ARRAY_SIZE(dc_ed_info), res_pec); 230 if (id < 0) { 231 dev_err(dev, "failed to get instance number: %d\n", id); 232 return id; 233 } 234 235 switch (id) { 236 case 0: 237 dc_drm->ed_cont[0] = ed; 238 break; 239 case 1: 240 dc_drm->ed_cont[1] = ed; 241 break; 242 case 4: 243 dc_drm->ed_safe[0] = ed; 244 break; 245 case 5: 246 dc_drm->ed_safe[1] = ed; 247 break; 248 } 249 250 return 0; 251} 252 253static const struct component_ops dc_ed_ops = { 254 .bind = dc_ed_bind, 255}; 256 257static int dc_ed_probe(struct platform_device *pdev) 258{ 259 int ret; 260 261 ret = component_add(&pdev->dev, &dc_ed_ops); 262 if (ret) 263 return dev_err_probe(&pdev->dev, ret, 264 "failed to add component\n"); 265 266 return 0; 267} 268 269static void dc_ed_remove(struct platform_device *pdev) 270{ 271 component_del(&pdev->dev, &dc_ed_ops); 272} 273 274static const struct of_device_id dc_ed_dt_ids[] = { 275 { .compatible = "fsl,imx8qxp-dc-extdst" }, 276 { /* sentinel */ } 277}; 278MODULE_DEVICE_TABLE(of, dc_ed_dt_ids); 279 280struct platform_driver dc_ed_driver = { 281 .probe = dc_ed_probe, 282 .remove = dc_ed_remove, 283 .driver = { 284 .name = "imx8-dc-extdst", 285 .suppress_bind_attrs = true, 286 .of_match_table = dc_ed_dt_ids, 287 }, 288};