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