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