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