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/ioport.h> 10*0e177d5cSLiu Ying #include <linux/mod_devicetable.h> 11*0e177d5cSLiu Ying #include <linux/module.h> 12*0e177d5cSLiu Ying #include <linux/platform_device.h> 13*0e177d5cSLiu Ying #include <linux/regmap.h> 14*0e177d5cSLiu Ying 15*0e177d5cSLiu Ying #include "dc-drv.h" 16*0e177d5cSLiu Ying #include "dc-pe.h" 17*0e177d5cSLiu Ying 18*0e177d5cSLiu Ying #define STATICCONTROL 0x8 19*0e177d5cSLiu Ying 20*0e177d5cSLiu Ying #define FRAMEDIMENSIONS 0xc 21*0e177d5cSLiu Ying #define HEIGHT(x) FIELD_PREP(GENMASK(29, 16), ((x) - 1)) 22*0e177d5cSLiu Ying #define WIDTH(x) FIELD_PREP(GENMASK(13, 0), ((x) - 1)) 23*0e177d5cSLiu Ying 24*0e177d5cSLiu Ying #define CONSTANTCOLOR 0x10 25*0e177d5cSLiu Ying #define BLUE(x) FIELD_PREP(GENMASK(15, 8), (x)) 26*0e177d5cSLiu Ying 27*0e177d5cSLiu Ying static const struct dc_subdev_info dc_cf_info[] = { 28*0e177d5cSLiu Ying { .reg_start = 0x56180960, .id = 0, }, 29*0e177d5cSLiu Ying { .reg_start = 0x561809e0, .id = 1, }, 30*0e177d5cSLiu Ying { .reg_start = 0x561809a0, .id = 4, }, 31*0e177d5cSLiu Ying { .reg_start = 0x56180a20, .id = 5, }, 32*0e177d5cSLiu Ying }; 33*0e177d5cSLiu Ying 34*0e177d5cSLiu Ying static const struct regmap_range dc_cf_regmap_ranges[] = { 35*0e177d5cSLiu Ying regmap_reg_range(STATICCONTROL, CONSTANTCOLOR), 36*0e177d5cSLiu Ying }; 37*0e177d5cSLiu Ying 38*0e177d5cSLiu Ying static const struct regmap_access_table dc_cf_regmap_access_table = { 39*0e177d5cSLiu Ying .yes_ranges = dc_cf_regmap_ranges, 40*0e177d5cSLiu Ying .n_yes_ranges = ARRAY_SIZE(dc_cf_regmap_ranges), 41*0e177d5cSLiu Ying }; 42*0e177d5cSLiu Ying 43*0e177d5cSLiu Ying static const struct regmap_config dc_cf_cfg_regmap_config = { 44*0e177d5cSLiu Ying .name = "cfg", 45*0e177d5cSLiu Ying .reg_bits = 32, 46*0e177d5cSLiu Ying .reg_stride = 4, 47*0e177d5cSLiu Ying .val_bits = 32, 48*0e177d5cSLiu Ying .fast_io = true, 49*0e177d5cSLiu Ying .wr_table = &dc_cf_regmap_access_table, 50*0e177d5cSLiu Ying .rd_table = &dc_cf_regmap_access_table, 51*0e177d5cSLiu Ying .max_register = CONSTANTCOLOR, 52*0e177d5cSLiu Ying }; 53*0e177d5cSLiu Ying 54*0e177d5cSLiu Ying static inline void dc_cf_enable_shden(struct dc_cf *cf) 55*0e177d5cSLiu Ying { 56*0e177d5cSLiu Ying regmap_write(cf->reg_cfg, STATICCONTROL, SHDEN); 57*0e177d5cSLiu Ying } 58*0e177d5cSLiu Ying 59*0e177d5cSLiu Ying enum dc_link_id dc_cf_get_link_id(struct dc_cf *cf) 60*0e177d5cSLiu Ying { 61*0e177d5cSLiu Ying return cf->link; 62*0e177d5cSLiu Ying } 63*0e177d5cSLiu Ying 64*0e177d5cSLiu Ying void dc_cf_framedimensions(struct dc_cf *cf, unsigned int w, 65*0e177d5cSLiu Ying unsigned int h) 66*0e177d5cSLiu Ying { 67*0e177d5cSLiu Ying regmap_write(cf->reg_cfg, FRAMEDIMENSIONS, WIDTH(w) | HEIGHT(h)); 68*0e177d5cSLiu Ying } 69*0e177d5cSLiu Ying 70*0e177d5cSLiu Ying void dc_cf_constantcolor_black(struct dc_cf *cf) 71*0e177d5cSLiu Ying { 72*0e177d5cSLiu Ying regmap_write(cf->reg_cfg, CONSTANTCOLOR, 0); 73*0e177d5cSLiu Ying } 74*0e177d5cSLiu Ying 75*0e177d5cSLiu Ying void dc_cf_constantcolor_blue(struct dc_cf *cf) 76*0e177d5cSLiu Ying { 77*0e177d5cSLiu Ying regmap_write(cf->reg_cfg, CONSTANTCOLOR, BLUE(0xff)); 78*0e177d5cSLiu Ying } 79*0e177d5cSLiu Ying 80*0e177d5cSLiu Ying void dc_cf_init(struct dc_cf *cf) 81*0e177d5cSLiu Ying { 82*0e177d5cSLiu Ying dc_cf_enable_shden(cf); 83*0e177d5cSLiu Ying } 84*0e177d5cSLiu Ying 85*0e177d5cSLiu Ying static int dc_cf_bind(struct device *dev, struct device *master, void *data) 86*0e177d5cSLiu Ying { 87*0e177d5cSLiu Ying struct platform_device *pdev = to_platform_device(dev); 88*0e177d5cSLiu Ying struct dc_drm_device *dc_drm = data; 89*0e177d5cSLiu Ying struct resource *res_pec; 90*0e177d5cSLiu Ying void __iomem *base_cfg; 91*0e177d5cSLiu Ying struct dc_cf *cf; 92*0e177d5cSLiu Ying int id; 93*0e177d5cSLiu Ying 94*0e177d5cSLiu Ying cf = devm_kzalloc(dev, sizeof(*cf), GFP_KERNEL); 95*0e177d5cSLiu Ying if (!cf) 96*0e177d5cSLiu Ying return -ENOMEM; 97*0e177d5cSLiu Ying 98*0e177d5cSLiu Ying res_pec = platform_get_resource(pdev, IORESOURCE_MEM, 0); 99*0e177d5cSLiu Ying 100*0e177d5cSLiu Ying base_cfg = devm_platform_ioremap_resource_byname(pdev, "cfg"); 101*0e177d5cSLiu Ying if (IS_ERR(base_cfg)) 102*0e177d5cSLiu Ying return PTR_ERR(base_cfg); 103*0e177d5cSLiu Ying 104*0e177d5cSLiu Ying cf->reg_cfg = devm_regmap_init_mmio(dev, base_cfg, 105*0e177d5cSLiu Ying &dc_cf_cfg_regmap_config); 106*0e177d5cSLiu Ying if (IS_ERR(cf->reg_cfg)) 107*0e177d5cSLiu Ying return PTR_ERR(cf->reg_cfg); 108*0e177d5cSLiu Ying 109*0e177d5cSLiu Ying id = dc_subdev_get_id(dc_cf_info, ARRAY_SIZE(dc_cf_info), res_pec); 110*0e177d5cSLiu Ying if (id < 0) { 111*0e177d5cSLiu Ying dev_err(dev, "failed to get instance number: %d\n", id); 112*0e177d5cSLiu Ying return id; 113*0e177d5cSLiu Ying } 114*0e177d5cSLiu Ying 115*0e177d5cSLiu Ying switch (id) { 116*0e177d5cSLiu Ying case 0: 117*0e177d5cSLiu Ying cf->link = LINK_ID_CONSTFRAME0; 118*0e177d5cSLiu Ying dc_drm->cf_cont[0] = cf; 119*0e177d5cSLiu Ying break; 120*0e177d5cSLiu Ying case 1: 121*0e177d5cSLiu Ying cf->link = LINK_ID_CONSTFRAME1; 122*0e177d5cSLiu Ying dc_drm->cf_cont[1] = cf; 123*0e177d5cSLiu Ying break; 124*0e177d5cSLiu Ying case 4: 125*0e177d5cSLiu Ying cf->link = LINK_ID_CONSTFRAME4; 126*0e177d5cSLiu Ying dc_drm->cf_safe[0] = cf; 127*0e177d5cSLiu Ying break; 128*0e177d5cSLiu Ying case 5: 129*0e177d5cSLiu Ying cf->link = LINK_ID_CONSTFRAME5; 130*0e177d5cSLiu Ying dc_drm->cf_safe[1] = cf; 131*0e177d5cSLiu Ying break; 132*0e177d5cSLiu Ying } 133*0e177d5cSLiu Ying 134*0e177d5cSLiu Ying return 0; 135*0e177d5cSLiu Ying } 136*0e177d5cSLiu Ying 137*0e177d5cSLiu Ying static const struct component_ops dc_cf_ops = { 138*0e177d5cSLiu Ying .bind = dc_cf_bind, 139*0e177d5cSLiu Ying }; 140*0e177d5cSLiu Ying 141*0e177d5cSLiu Ying static int dc_cf_probe(struct platform_device *pdev) 142*0e177d5cSLiu Ying { 143*0e177d5cSLiu Ying int ret; 144*0e177d5cSLiu Ying 145*0e177d5cSLiu Ying ret = component_add(&pdev->dev, &dc_cf_ops); 146*0e177d5cSLiu Ying if (ret) 147*0e177d5cSLiu Ying return dev_err_probe(&pdev->dev, ret, 148*0e177d5cSLiu Ying "failed to add component\n"); 149*0e177d5cSLiu Ying 150*0e177d5cSLiu Ying return 0; 151*0e177d5cSLiu Ying } 152*0e177d5cSLiu Ying 153*0e177d5cSLiu Ying static void dc_cf_remove(struct platform_device *pdev) 154*0e177d5cSLiu Ying { 155*0e177d5cSLiu Ying component_del(&pdev->dev, &dc_cf_ops); 156*0e177d5cSLiu Ying } 157*0e177d5cSLiu Ying 158*0e177d5cSLiu Ying static const struct of_device_id dc_cf_dt_ids[] = { 159*0e177d5cSLiu Ying { .compatible = "fsl,imx8qxp-dc-constframe" }, 160*0e177d5cSLiu Ying { /* sentinel */ } 161*0e177d5cSLiu Ying }; 162*0e177d5cSLiu Ying MODULE_DEVICE_TABLE(of, dc_cf_dt_ids); 163*0e177d5cSLiu Ying 164*0e177d5cSLiu Ying struct platform_driver dc_cf_driver = { 165*0e177d5cSLiu Ying .probe = dc_cf_probe, 166*0e177d5cSLiu Ying .remove = dc_cf_remove, 167*0e177d5cSLiu Ying .driver = { 168*0e177d5cSLiu Ying .name = "imx8-dc-constframe", 169*0e177d5cSLiu Ying .suppress_bind_attrs = true, 170*0e177d5cSLiu Ying .of_match_table = dc_cf_dt_ids, 171*0e177d5cSLiu Ying }, 172*0e177d5cSLiu Ying }; 173