1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2025 Icenowy Zheng <uwu@icenowy.me> 4 */ 5 6 #include <linux/dma-mapping.h> 7 #include <linux/irqreturn.h> 8 #include <linux/of.h> 9 #include <linux/of_graph.h> 10 11 #include "vs_crtc.h" 12 #include "vs_dc.h" 13 #include "vs_dc_top_regs.h" 14 #include "vs_drm.h" 15 #include "vs_hwdb.h" 16 17 static const struct regmap_config vs_dc_regmap_cfg = { 18 .reg_bits = 32, 19 .val_bits = 32, 20 .reg_stride = sizeof(u32), 21 /* VSDC_OVL_CONFIG_EX(1) */ 22 .max_register = 0x2544, 23 }; 24 25 static const struct of_device_id vs_dc_driver_dt_match[] = { 26 { .compatible = "verisilicon,dc" }, 27 {}, 28 }; 29 MODULE_DEVICE_TABLE(of, vs_dc_driver_dt_match); 30 31 static irqreturn_t vs_dc_irq_handler(int irq, void *private) 32 { 33 struct vs_dc *dc = private; 34 u32 irqs; 35 36 regmap_read(dc->regs, VSDC_TOP_IRQ_ACK, &irqs); 37 38 vs_drm_handle_irq(dc, irqs); 39 40 return IRQ_HANDLED; 41 } 42 43 static int vs_dc_probe(struct platform_device *pdev) 44 { 45 struct device *dev = &pdev->dev; 46 struct vs_dc *dc; 47 void __iomem *regs; 48 unsigned int port_count, i; 49 /* pix%u */ 50 char pixclk_name[14]; 51 int irq, ret; 52 53 if (!dev->of_node) { 54 dev_err(dev, "can't find DC devices\n"); 55 return -ENODEV; 56 } 57 58 port_count = of_graph_get_port_count(dev->of_node); 59 if (!port_count) { 60 dev_err(dev, "can't find DC downstream ports\n"); 61 return -ENODEV; 62 } 63 if (port_count > VSDC_MAX_OUTPUTS) { 64 dev_err(dev, "too many DC downstream ports than possible\n"); 65 return -EINVAL; 66 } 67 68 ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 69 if (ret) { 70 dev_err(dev, "No suitable DMA available\n"); 71 return ret; 72 } 73 74 dc = devm_kzalloc(dev, sizeof(*dc), GFP_KERNEL); 75 if (!dc) 76 return -ENOMEM; 77 78 dc->rsts[0].id = "core"; 79 dc->rsts[1].id = "axi"; 80 dc->rsts[2].id = "ahb"; 81 82 ret = devm_reset_control_bulk_get_optional_shared(dev, VSDC_RESET_COUNT, 83 dc->rsts); 84 if (ret) { 85 dev_err(dev, "can't get reset lines\n"); 86 return ret; 87 } 88 89 dc->core_clk = devm_clk_get_enabled(dev, "core"); 90 if (IS_ERR(dc->core_clk)) { 91 dev_err(dev, "can't get core clock\n"); 92 return PTR_ERR(dc->core_clk); 93 } 94 95 dc->axi_clk = devm_clk_get_enabled(dev, "axi"); 96 if (IS_ERR(dc->axi_clk)) { 97 dev_err(dev, "can't get axi clock\n"); 98 return PTR_ERR(dc->axi_clk); 99 } 100 101 dc->ahb_clk = devm_clk_get_enabled(dev, "ahb"); 102 if (IS_ERR(dc->ahb_clk)) { 103 dev_err(dev, "can't get ahb clock\n"); 104 return PTR_ERR(dc->ahb_clk); 105 } 106 107 irq = platform_get_irq(pdev, 0); 108 if (irq < 0) { 109 dev_err(dev, "can't get irq\n"); 110 return irq; 111 } 112 113 ret = reset_control_bulk_deassert(VSDC_RESET_COUNT, dc->rsts); 114 if (ret) { 115 dev_err(dev, "can't deassert reset lines\n"); 116 return ret; 117 } 118 119 regs = devm_platform_ioremap_resource(pdev, 0); 120 if (IS_ERR(regs)) { 121 dev_err(dev, "can't map registers"); 122 ret = PTR_ERR(regs); 123 goto err_rst_assert; 124 } 125 126 dc->regs = devm_regmap_init_mmio(dev, regs, &vs_dc_regmap_cfg); 127 if (IS_ERR(dc->regs)) { 128 ret = PTR_ERR(dc->regs); 129 goto err_rst_assert; 130 } 131 132 ret = vs_fill_chip_identity(dc->regs, &dc->identity); 133 if (ret) 134 goto err_rst_assert; 135 136 dev_info(dev, "Found DC%x rev %x customer %x\n", dc->identity.model, 137 dc->identity.revision, dc->identity.customer_id); 138 139 if (port_count > dc->identity.display_count) { 140 dev_err(dev, "too many downstream ports than HW capability\n"); 141 ret = -EINVAL; 142 goto err_rst_assert; 143 } 144 145 for (i = 0; i < dc->identity.display_count; i++) { 146 snprintf(pixclk_name, sizeof(pixclk_name), "pix%u", i); 147 dc->pix_clk[i] = devm_clk_get(dev, pixclk_name); 148 if (IS_ERR(dc->pix_clk[i])) { 149 dev_err(dev, "can't get pixel clk %u\n", i); 150 ret = PTR_ERR(dc->pix_clk[i]); 151 goto err_rst_assert; 152 } 153 } 154 155 ret = devm_request_irq(dev, irq, vs_dc_irq_handler, 0, 156 dev_name(dev), dc); 157 if (ret) { 158 dev_err(dev, "can't request irq\n"); 159 goto err_rst_assert; 160 } 161 162 dev_set_drvdata(dev, dc); 163 164 ret = vs_drm_initialize(dc, pdev); 165 if (ret) 166 goto err_rst_assert; 167 168 return 0; 169 170 err_rst_assert: 171 reset_control_bulk_assert(VSDC_RESET_COUNT, dc->rsts); 172 return ret; 173 } 174 175 static void vs_dc_remove(struct platform_device *pdev) 176 { 177 struct vs_dc *dc = dev_get_drvdata(&pdev->dev); 178 179 vs_drm_finalize(dc); 180 181 dev_set_drvdata(&pdev->dev, NULL); 182 183 reset_control_bulk_assert(VSDC_RESET_COUNT, dc->rsts); 184 } 185 186 static void vs_dc_shutdown(struct platform_device *pdev) 187 { 188 struct vs_dc *dc = dev_get_drvdata(&pdev->dev); 189 190 vs_drm_shutdown_handler(dc); 191 } 192 193 static struct platform_driver vs_dc_platform_driver = { 194 .probe = vs_dc_probe, 195 .remove = vs_dc_remove, 196 .shutdown = vs_dc_shutdown, 197 .driver = { 198 .name = "verisilicon-dc", 199 .of_match_table = vs_dc_driver_dt_match, 200 }, 201 }; 202 203 module_platform_driver(vs_dc_platform_driver); 204 205 MODULE_AUTHOR("Icenowy Zheng <uwu@icenowy.me>"); 206 MODULE_DESCRIPTION("Verisilicon display controller driver"); 207 MODULE_LICENSE("GPL"); 208