1*9f09e317SLiu Ying // SPDX-License-Identifier: GPL-2.0+ 2*9f09e317SLiu Ying /* 3*9f09e317SLiu Ying * Copyright 2024 NXP 4*9f09e317SLiu Ying */ 5*9f09e317SLiu Ying 6*9f09e317SLiu Ying #include <linux/component.h> 7*9f09e317SLiu Ying #include <linux/mod_devicetable.h> 8*9f09e317SLiu Ying #include <linux/module.h> 9*9f09e317SLiu Ying #include <linux/platform_device.h> 10*9f09e317SLiu Ying #include <linux/regmap.h> 11*9f09e317SLiu Ying 12*9f09e317SLiu Ying #include "dc-drv.h" 13*9f09e317SLiu Ying #include "dc-de.h" 14*9f09e317SLiu Ying 15*9f09e317SLiu Ying #define TCON_CTRL 0x410 16*9f09e317SLiu Ying #define CTRL_RST_VAL 0x01401408 17*9f09e317SLiu Ying 18*9f09e317SLiu Ying /* red: MAPBIT 29-20, green: MAPBIT 19-10, blue: MAPBIT 9-0 */ 19*9f09e317SLiu Ying #define MAPBIT3_0 0x418 20*9f09e317SLiu Ying #define MAPBIT7_4 0x41c 21*9f09e317SLiu Ying #define MAPBIT11_8 0x420 22*9f09e317SLiu Ying #define MAPBIT15_12 0x424 23*9f09e317SLiu Ying #define MAPBIT19_16 0x428 24*9f09e317SLiu Ying #define MAPBIT23_20 0x42c 25*9f09e317SLiu Ying #define MAPBIT27_24 0x430 26*9f09e317SLiu Ying #define MAPBIT31_28 0x434 27*9f09e317SLiu Ying 28*9f09e317SLiu Ying static const struct dc_subdev_info dc_tc_info[] = { 29*9f09e317SLiu Ying { .reg_start = 0x5618c800, .id = 0, }, 30*9f09e317SLiu Ying { .reg_start = 0x5618e400, .id = 1, }, 31*9f09e317SLiu Ying }; 32*9f09e317SLiu Ying 33*9f09e317SLiu Ying static const struct regmap_range dc_tc_regmap_ranges[] = { 34*9f09e317SLiu Ying regmap_reg_range(TCON_CTRL, TCON_CTRL), 35*9f09e317SLiu Ying regmap_reg_range(MAPBIT3_0, MAPBIT31_28), 36*9f09e317SLiu Ying }; 37*9f09e317SLiu Ying 38*9f09e317SLiu Ying static const struct regmap_access_table dc_tc_regmap_access_table = { 39*9f09e317SLiu Ying .yes_ranges = dc_tc_regmap_ranges, 40*9f09e317SLiu Ying .n_yes_ranges = ARRAY_SIZE(dc_tc_regmap_ranges), 41*9f09e317SLiu Ying }; 42*9f09e317SLiu Ying 43*9f09e317SLiu Ying static const struct regmap_config dc_tc_regmap_config = { 44*9f09e317SLiu Ying .reg_bits = 32, 45*9f09e317SLiu Ying .reg_stride = 4, 46*9f09e317SLiu Ying .val_bits = 32, 47*9f09e317SLiu Ying .fast_io = true, 48*9f09e317SLiu Ying .wr_table = &dc_tc_regmap_access_table, 49*9f09e317SLiu Ying .rd_table = &dc_tc_regmap_access_table, 50*9f09e317SLiu Ying .max_register = MAPBIT31_28, 51*9f09e317SLiu Ying }; 52*9f09e317SLiu Ying 53*9f09e317SLiu Ying /* 54*9f09e317SLiu Ying * The pixels reach TCON are always in 30-bit BGR format. 55*9f09e317SLiu Ying * The first bridge always receives pixels in 30-bit RGB format. 56*9f09e317SLiu Ying * So, map the format to MEDIA_BUS_FMT_RGB101010_1X30. 57*9f09e317SLiu Ying */ 58*9f09e317SLiu Ying static const u32 dc_tc_mapbit[] = { 59*9f09e317SLiu Ying 0x17161514, 0x1b1a1918, 0x0b0a1d1c, 0x0f0e0d0c, 60*9f09e317SLiu Ying 0x13121110, 0x03020100, 0x07060504, 0x00000908, 61*9f09e317SLiu Ying }; 62*9f09e317SLiu Ying 63*9f09e317SLiu Ying void dc_tc_init(struct dc_tc *tc) 64*9f09e317SLiu Ying { 65*9f09e317SLiu Ying /* reset TCON_CTRL to POR default so that TCON works in bypass mode */ 66*9f09e317SLiu Ying regmap_write(tc->reg, TCON_CTRL, CTRL_RST_VAL); 67*9f09e317SLiu Ying 68*9f09e317SLiu Ying /* set format */ 69*9f09e317SLiu Ying regmap_bulk_write(tc->reg, MAPBIT3_0, dc_tc_mapbit, 70*9f09e317SLiu Ying ARRAY_SIZE(dc_tc_mapbit)); 71*9f09e317SLiu Ying } 72*9f09e317SLiu Ying 73*9f09e317SLiu Ying static int dc_tc_bind(struct device *dev, struct device *master, void *data) 74*9f09e317SLiu Ying { 75*9f09e317SLiu Ying struct platform_device *pdev = to_platform_device(dev); 76*9f09e317SLiu Ying struct dc_drm_device *dc_drm = data; 77*9f09e317SLiu Ying struct resource *res; 78*9f09e317SLiu Ying void __iomem *base; 79*9f09e317SLiu Ying struct dc_tc *tc; 80*9f09e317SLiu Ying int id; 81*9f09e317SLiu Ying 82*9f09e317SLiu Ying tc = devm_kzalloc(dev, sizeof(*tc), GFP_KERNEL); 83*9f09e317SLiu Ying if (!tc) 84*9f09e317SLiu Ying return -ENOMEM; 85*9f09e317SLiu Ying 86*9f09e317SLiu Ying base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 87*9f09e317SLiu Ying if (IS_ERR(base)) 88*9f09e317SLiu Ying return PTR_ERR(base); 89*9f09e317SLiu Ying 90*9f09e317SLiu Ying tc->reg = devm_regmap_init_mmio(dev, base, &dc_tc_regmap_config); 91*9f09e317SLiu Ying if (IS_ERR(tc->reg)) 92*9f09e317SLiu Ying return PTR_ERR(tc->reg); 93*9f09e317SLiu Ying 94*9f09e317SLiu Ying id = dc_subdev_get_id(dc_tc_info, ARRAY_SIZE(dc_tc_info), res); 95*9f09e317SLiu Ying if (id < 0) { 96*9f09e317SLiu Ying dev_err(dev, "failed to get instance number: %d\n", id); 97*9f09e317SLiu Ying return id; 98*9f09e317SLiu Ying } 99*9f09e317SLiu Ying 100*9f09e317SLiu Ying tc->dev = dev; 101*9f09e317SLiu Ying dc_drm->tc[id] = tc; 102*9f09e317SLiu Ying 103*9f09e317SLiu Ying return 0; 104*9f09e317SLiu Ying } 105*9f09e317SLiu Ying 106*9f09e317SLiu Ying static const struct component_ops dc_tc_ops = { 107*9f09e317SLiu Ying .bind = dc_tc_bind, 108*9f09e317SLiu Ying }; 109*9f09e317SLiu Ying 110*9f09e317SLiu Ying static int dc_tc_probe(struct platform_device *pdev) 111*9f09e317SLiu Ying { 112*9f09e317SLiu Ying int ret; 113*9f09e317SLiu Ying 114*9f09e317SLiu Ying ret = component_add(&pdev->dev, &dc_tc_ops); 115*9f09e317SLiu Ying if (ret) 116*9f09e317SLiu Ying return dev_err_probe(&pdev->dev, ret, 117*9f09e317SLiu Ying "failed to add component\n"); 118*9f09e317SLiu Ying 119*9f09e317SLiu Ying return 0; 120*9f09e317SLiu Ying } 121*9f09e317SLiu Ying 122*9f09e317SLiu Ying static void dc_tc_remove(struct platform_device *pdev) 123*9f09e317SLiu Ying { 124*9f09e317SLiu Ying component_del(&pdev->dev, &dc_tc_ops); 125*9f09e317SLiu Ying } 126*9f09e317SLiu Ying 127*9f09e317SLiu Ying static const struct of_device_id dc_tc_dt_ids[] = { 128*9f09e317SLiu Ying { .compatible = "fsl,imx8qxp-dc-tcon" }, 129*9f09e317SLiu Ying { /* sentinel */ } 130*9f09e317SLiu Ying }; 131*9f09e317SLiu Ying MODULE_DEVICE_TABLE(of, dc_tc_dt_ids); 132*9f09e317SLiu Ying 133*9f09e317SLiu Ying struct platform_driver dc_tc_driver = { 134*9f09e317SLiu Ying .probe = dc_tc_probe, 135*9f09e317SLiu Ying .remove = dc_tc_remove, 136*9f09e317SLiu Ying .driver = { 137*9f09e317SLiu Ying .name = "imx8-dc-tcon", 138*9f09e317SLiu Ying .suppress_bind_attrs = true, 139*9f09e317SLiu Ying .of_match_table = dc_tc_dt_ids, 140*9f09e317SLiu Ying }, 141*9f09e317SLiu Ying }; 142