1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright 2024 NXP 4 */ 5 6 #include <linux/component.h> 7 #include <linux/module.h> 8 #include <linux/platform_device.h> 9 #include <linux/regmap.h> 10 11 #include <drm/drm_fourcc.h> 12 13 #include "dc-drv.h" 14 #include "dc-fu.h" 15 16 #define PIXENGCFG_DYNAMIC 0x8 17 18 #define BASEADDRESS(x) (0x10 + FRAC_OFFSET * (x)) 19 #define SOURCEBUFFERATTRIBUTES(x) (0x14 + FRAC_OFFSET * (x)) 20 #define SOURCEBUFFERDIMENSION(x) (0x18 + FRAC_OFFSET * (x)) 21 #define COLORCOMPONENTBITS(x) (0x1c + FRAC_OFFSET * (x)) 22 #define COLORCOMPONENTSHIFT(x) (0x20 + FRAC_OFFSET * (x)) 23 #define LAYEROFFSET(x) (0x24 + FRAC_OFFSET * (x)) 24 #define CLIPWINDOWOFFSET(x) (0x28 + FRAC_OFFSET * (x)) 25 #define CLIPWINDOWDIMENSIONS(x) (0x2c + FRAC_OFFSET * (x)) 26 #define CONSTANTCOLOR(x) (0x30 + FRAC_OFFSET * (x)) 27 #define LAYERPROPERTY(x) (0x34 + FRAC_OFFSET * (x)) 28 #define FRAMEDIMENSIONS 0x150 29 #define CONTROL 0x170 30 31 struct dc_fw { 32 struct dc_fu fu; 33 }; 34 35 static const struct dc_subdev_info dc_fw_info[] = { 36 { .reg_start = 0x56180a60, .id = 2, }, 37 }; 38 39 static const struct regmap_range dc_fw_pec_regmap_access_ranges[] = { 40 regmap_reg_range(PIXENGCFG_DYNAMIC, PIXENGCFG_DYNAMIC), 41 }; 42 43 static const struct regmap_access_table dc_fw_pec_regmap_access_table = { 44 .yes_ranges = dc_fw_pec_regmap_access_ranges, 45 .n_yes_ranges = ARRAY_SIZE(dc_fw_pec_regmap_access_ranges), 46 }; 47 48 static const struct regmap_config dc_fw_pec_regmap_config = { 49 .name = "pec", 50 .reg_bits = 32, 51 .reg_stride = 4, 52 .val_bits = 32, 53 .fast_io = true, 54 .wr_table = &dc_fw_pec_regmap_access_table, 55 .rd_table = &dc_fw_pec_regmap_access_table, 56 .max_register = PIXENGCFG_DYNAMIC, 57 }; 58 59 static const struct regmap_range dc_fw_regmap_ranges[] = { 60 regmap_reg_range(STATICCONTROL, FRAMEDIMENSIONS), 61 regmap_reg_range(CONTROL, CONTROL), 62 }; 63 64 static const struct regmap_access_table dc_fw_regmap_access_table = { 65 .yes_ranges = dc_fw_regmap_ranges, 66 .n_yes_ranges = ARRAY_SIZE(dc_fw_regmap_ranges), 67 }; 68 69 static const struct regmap_config dc_fw_cfg_regmap_config = { 70 .name = "cfg", 71 .reg_bits = 32, 72 .reg_stride = 4, 73 .val_bits = 32, 74 .fast_io = true, 75 .wr_table = &dc_fw_regmap_access_table, 76 .rd_table = &dc_fw_regmap_access_table, 77 .max_register = CONTROL, 78 }; 79 80 static void dc_fw_set_fmt(struct dc_fu *fu, enum dc_fu_frac frac, 81 const struct drm_format_info *format) 82 { 83 u32 bits = 0, shifts = 0; 84 85 dc_fu_set_src_bpp(fu, frac, format->cpp[0] * 8); 86 87 regmap_write_bits(fu->reg_cfg, CONTROL, INPUTSELECT_MASK, 88 INPUTSELECT(INPUTSELECT_INACTIVE)); 89 regmap_write_bits(fu->reg_cfg, CONTROL, RASTERMODE_MASK, 90 RASTERMODE(RASTERMODE_NORMAL)); 91 92 regmap_write_bits(fu->reg_cfg, LAYERPROPERTY(frac), 93 YUVCONVERSIONMODE_MASK, 94 YUVCONVERSIONMODE(YUVCONVERSIONMODE_OFF)); 95 96 dc_fu_get_pixel_format_bits(fu, format->format, &bits); 97 dc_fu_get_pixel_format_shifts(fu, format->format, &shifts); 98 99 regmap_write(fu->reg_cfg, COLORCOMPONENTBITS(frac), bits); 100 regmap_write(fu->reg_cfg, COLORCOMPONENTSHIFT(frac), shifts); 101 } 102 103 static void dc_fw_set_framedimensions(struct dc_fu *fu, int w, int h) 104 { 105 regmap_write(fu->reg_cfg, FRAMEDIMENSIONS, 106 FRAMEWIDTH(w) | FRAMEHEIGHT(h)); 107 } 108 109 static void dc_fw_init(struct dc_fu *fu) 110 { 111 regmap_write(fu->reg_pec, PIXENGCFG_DYNAMIC, LINK_ID_NONE); 112 dc_fu_common_hw_init(fu); 113 dc_fu_shdldreq_sticky(fu, 0xff); 114 } 115 116 static void dc_fw_set_ops(struct dc_fu *fu) 117 { 118 memcpy(&fu->ops, &dc_fu_common_ops, sizeof(dc_fu_common_ops)); 119 fu->ops.init = dc_fw_init; 120 fu->ops.set_fmt = dc_fw_set_fmt; 121 fu->ops.set_framedimensions = dc_fw_set_framedimensions; 122 } 123 124 static int dc_fw_bind(struct device *dev, struct device *master, void *data) 125 { 126 struct platform_device *pdev = to_platform_device(dev); 127 struct dc_drm_device *dc_drm = data; 128 struct resource *res_pec; 129 void __iomem *base_pec; 130 void __iomem *base_cfg; 131 struct dc_fw *fw; 132 struct dc_fu *fu; 133 int i, id; 134 135 fw = devm_kzalloc(dev, sizeof(*fw), GFP_KERNEL); 136 if (!fw) 137 return -ENOMEM; 138 139 fu = &fw->fu; 140 141 base_pec = devm_platform_get_and_ioremap_resource(pdev, 0, &res_pec); 142 if (IS_ERR(base_pec)) 143 return PTR_ERR(base_pec); 144 145 base_cfg = devm_platform_ioremap_resource_byname(pdev, "cfg"); 146 if (IS_ERR(base_cfg)) 147 return PTR_ERR(base_cfg); 148 149 fu->reg_pec = devm_regmap_init_mmio(dev, base_pec, 150 &dc_fw_pec_regmap_config); 151 if (IS_ERR(fu->reg_pec)) 152 return PTR_ERR(fu->reg_pec); 153 154 fu->reg_cfg = devm_regmap_init_mmio(dev, base_cfg, 155 &dc_fw_cfg_regmap_config); 156 if (IS_ERR(fu->reg_cfg)) 157 return PTR_ERR(fu->reg_cfg); 158 159 id = dc_subdev_get_id(dc_fw_info, ARRAY_SIZE(dc_fw_info), res_pec); 160 if (id < 0) { 161 dev_err(dev, "failed to get instance number: %d\n", id); 162 return id; 163 } 164 165 fu->link_id = LINK_ID_FETCHWARP2; 166 fu->id = DC_FETCHUNIT_FW2; 167 for (i = 0; i < DC_FETCHUNIT_FRAC_NUM; i++) { 168 fu->reg_baseaddr[i] = BASEADDRESS(i); 169 fu->reg_sourcebufferattributes[i] = SOURCEBUFFERATTRIBUTES(i); 170 fu->reg_sourcebufferdimension[i] = SOURCEBUFFERDIMENSION(i); 171 fu->reg_layeroffset[i] = LAYEROFFSET(i); 172 fu->reg_clipwindowoffset[i] = CLIPWINDOWOFFSET(i); 173 fu->reg_clipwindowdimensions[i] = CLIPWINDOWDIMENSIONS(i); 174 fu->reg_constantcolor[i] = CONSTANTCOLOR(i); 175 fu->reg_layerproperty[i] = LAYERPROPERTY(i); 176 } 177 snprintf(fu->name, sizeof(fu->name), "FetchWarp%d", id); 178 179 dc_fw_set_ops(fu); 180 181 dc_drm->fu_disp[fu->id] = fu; 182 183 return 0; 184 } 185 186 static const struct component_ops dc_fw_ops = { 187 .bind = dc_fw_bind, 188 }; 189 190 static int dc_fw_probe(struct platform_device *pdev) 191 { 192 int ret; 193 194 ret = component_add(&pdev->dev, &dc_fw_ops); 195 if (ret) 196 return dev_err_probe(&pdev->dev, ret, 197 "failed to add component\n"); 198 199 return 0; 200 } 201 202 static void dc_fw_remove(struct platform_device *pdev) 203 { 204 component_del(&pdev->dev, &dc_fw_ops); 205 } 206 207 static const struct of_device_id dc_fw_dt_ids[] = { 208 { .compatible = "fsl,imx8qxp-dc-fetchwarp" }, 209 { /* sentinel */ } 210 }; 211 MODULE_DEVICE_TABLE(of, dc_fw_dt_ids); 212 213 struct platform_driver dc_fw_driver = { 214 .probe = dc_fw_probe, 215 .remove = dc_fw_remove, 216 .driver = { 217 .name = "imx8-dc-fetchwarp", 218 .suppress_bind_attrs = true, 219 .of_match_table = dc_fw_dt_ids, 220 }, 221 }; 222