1 /* 2 * Copyright (c) 2015 MediaTek Inc. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 14 #include <drm/drmP.h> 15 #include <linux/clk.h> 16 #include <linux/component.h> 17 #include <linux/of_device.h> 18 #include <linux/of_irq.h> 19 #include <linux/platform_device.h> 20 21 #include "mtk_drm_crtc.h" 22 #include "mtk_drm_ddp_comp.h" 23 24 #define DISP_REG_RDMA_INT_ENABLE 0x0000 25 #define DISP_REG_RDMA_INT_STATUS 0x0004 26 #define RDMA_TARGET_LINE_INT BIT(5) 27 #define RDMA_FIFO_UNDERFLOW_INT BIT(4) 28 #define RDMA_EOF_ABNORMAL_INT BIT(3) 29 #define RDMA_FRAME_END_INT BIT(2) 30 #define RDMA_FRAME_START_INT BIT(1) 31 #define RDMA_REG_UPDATE_INT BIT(0) 32 #define DISP_REG_RDMA_GLOBAL_CON 0x0010 33 #define RDMA_ENGINE_EN BIT(0) 34 #define DISP_REG_RDMA_SIZE_CON_0 0x0014 35 #define DISP_REG_RDMA_SIZE_CON_1 0x0018 36 #define DISP_REG_RDMA_TARGET_LINE 0x001c 37 #define DISP_REG_RDMA_FIFO_CON 0x0040 38 #define RDMA_FIFO_UNDERFLOW_EN BIT(31) 39 #define RDMA_FIFO_PSEUDO_SIZE(bytes) (((bytes) / 16) << 16) 40 #define RDMA_OUTPUT_VALID_FIFO_THRESHOLD(bytes) ((bytes) / 16) 41 #define RDMA_FIFO_SIZE(rdma) ((rdma)->data->fifo_size) 42 43 struct mtk_disp_rdma_data { 44 unsigned int fifo_size; 45 }; 46 47 /** 48 * struct mtk_disp_rdma - DISP_RDMA driver structure 49 * @ddp_comp - structure containing type enum and hardware resources 50 * @crtc - associated crtc to report irq events to 51 */ 52 struct mtk_disp_rdma { 53 struct mtk_ddp_comp ddp_comp; 54 struct drm_crtc *crtc; 55 const struct mtk_disp_rdma_data *data; 56 }; 57 58 static inline struct mtk_disp_rdma *comp_to_rdma(struct mtk_ddp_comp *comp) 59 { 60 return container_of(comp, struct mtk_disp_rdma, ddp_comp); 61 } 62 63 static irqreturn_t mtk_disp_rdma_irq_handler(int irq, void *dev_id) 64 { 65 struct mtk_disp_rdma *priv = dev_id; 66 struct mtk_ddp_comp *rdma = &priv->ddp_comp; 67 68 /* Clear frame completion interrupt */ 69 writel(0x0, rdma->regs + DISP_REG_RDMA_INT_STATUS); 70 71 if (!priv->crtc) 72 return IRQ_NONE; 73 74 mtk_crtc_ddp_irq(priv->crtc, rdma); 75 76 return IRQ_HANDLED; 77 } 78 79 static void rdma_update_bits(struct mtk_ddp_comp *comp, unsigned int reg, 80 unsigned int mask, unsigned int val) 81 { 82 unsigned int tmp = readl(comp->regs + reg); 83 84 tmp = (tmp & ~mask) | (val & mask); 85 writel(tmp, comp->regs + reg); 86 } 87 88 static void mtk_rdma_enable_vblank(struct mtk_ddp_comp *comp, 89 struct drm_crtc *crtc) 90 { 91 struct mtk_disp_rdma *rdma = comp_to_rdma(comp); 92 93 rdma->crtc = crtc; 94 rdma_update_bits(comp, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT, 95 RDMA_FRAME_END_INT); 96 } 97 98 static void mtk_rdma_disable_vblank(struct mtk_ddp_comp *comp) 99 { 100 struct mtk_disp_rdma *rdma = comp_to_rdma(comp); 101 102 rdma->crtc = NULL; 103 rdma_update_bits(comp, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT, 0); 104 } 105 106 static void mtk_rdma_start(struct mtk_ddp_comp *comp) 107 { 108 rdma_update_bits(comp, DISP_REG_RDMA_GLOBAL_CON, RDMA_ENGINE_EN, 109 RDMA_ENGINE_EN); 110 } 111 112 static void mtk_rdma_stop(struct mtk_ddp_comp *comp) 113 { 114 rdma_update_bits(comp, DISP_REG_RDMA_GLOBAL_CON, RDMA_ENGINE_EN, 0); 115 } 116 117 static void mtk_rdma_config(struct mtk_ddp_comp *comp, unsigned int width, 118 unsigned int height, unsigned int vrefresh, 119 unsigned int bpc) 120 { 121 unsigned int threshold; 122 unsigned int reg; 123 struct mtk_disp_rdma *rdma = comp_to_rdma(comp); 124 125 rdma_update_bits(comp, DISP_REG_RDMA_SIZE_CON_0, 0xfff, width); 126 rdma_update_bits(comp, DISP_REG_RDMA_SIZE_CON_1, 0xfffff, height); 127 128 /* 129 * Enable FIFO underflow since DSI and DPI can't be blocked. 130 * Keep the FIFO pseudo size reset default of 8 KiB. Set the 131 * output threshold to 6 microseconds with 7/6 overhead to 132 * account for blanking, and with a pixel depth of 4 bytes: 133 */ 134 threshold = width * height * vrefresh * 4 * 7 / 1000000; 135 reg = RDMA_FIFO_UNDERFLOW_EN | 136 RDMA_FIFO_PSEUDO_SIZE(RDMA_FIFO_SIZE(rdma)) | 137 RDMA_OUTPUT_VALID_FIFO_THRESHOLD(threshold); 138 writel(reg, comp->regs + DISP_REG_RDMA_FIFO_CON); 139 } 140 141 static const struct mtk_ddp_comp_funcs mtk_disp_rdma_funcs = { 142 .config = mtk_rdma_config, 143 .start = mtk_rdma_start, 144 .stop = mtk_rdma_stop, 145 .enable_vblank = mtk_rdma_enable_vblank, 146 .disable_vblank = mtk_rdma_disable_vblank, 147 }; 148 149 static int mtk_disp_rdma_bind(struct device *dev, struct device *master, 150 void *data) 151 { 152 struct mtk_disp_rdma *priv = dev_get_drvdata(dev); 153 struct drm_device *drm_dev = data; 154 int ret; 155 156 ret = mtk_ddp_comp_register(drm_dev, &priv->ddp_comp); 157 if (ret < 0) { 158 dev_err(dev, "Failed to register component %pOF: %d\n", 159 dev->of_node, ret); 160 return ret; 161 } 162 163 return 0; 164 165 } 166 167 static void mtk_disp_rdma_unbind(struct device *dev, struct device *master, 168 void *data) 169 { 170 struct mtk_disp_rdma *priv = dev_get_drvdata(dev); 171 struct drm_device *drm_dev = data; 172 173 mtk_ddp_comp_unregister(drm_dev, &priv->ddp_comp); 174 } 175 176 static const struct component_ops mtk_disp_rdma_component_ops = { 177 .bind = mtk_disp_rdma_bind, 178 .unbind = mtk_disp_rdma_unbind, 179 }; 180 181 static int mtk_disp_rdma_probe(struct platform_device *pdev) 182 { 183 struct device *dev = &pdev->dev; 184 struct mtk_disp_rdma *priv; 185 int comp_id; 186 int irq; 187 int ret; 188 189 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 190 if (!priv) 191 return -ENOMEM; 192 193 irq = platform_get_irq(pdev, 0); 194 if (irq < 0) 195 return irq; 196 197 comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DISP_RDMA); 198 if (comp_id < 0) { 199 dev_err(dev, "Failed to identify by alias: %d\n", comp_id); 200 return comp_id; 201 } 202 203 ret = mtk_ddp_comp_init(dev, dev->of_node, &priv->ddp_comp, comp_id, 204 &mtk_disp_rdma_funcs); 205 if (ret) { 206 dev_err(dev, "Failed to initialize component: %d\n", ret); 207 return ret; 208 } 209 210 /* Disable and clear pending interrupts */ 211 writel(0x0, priv->ddp_comp.regs + DISP_REG_RDMA_INT_ENABLE); 212 writel(0x0, priv->ddp_comp.regs + DISP_REG_RDMA_INT_STATUS); 213 214 ret = devm_request_irq(dev, irq, mtk_disp_rdma_irq_handler, 215 IRQF_TRIGGER_NONE, dev_name(dev), priv); 216 if (ret < 0) { 217 dev_err(dev, "Failed to request irq %d: %d\n", irq, ret); 218 return ret; 219 } 220 221 priv->data = of_device_get_match_data(dev); 222 223 platform_set_drvdata(pdev, priv); 224 225 ret = component_add(dev, &mtk_disp_rdma_component_ops); 226 if (ret) 227 dev_err(dev, "Failed to add component: %d\n", ret); 228 229 return ret; 230 } 231 232 static int mtk_disp_rdma_remove(struct platform_device *pdev) 233 { 234 component_del(&pdev->dev, &mtk_disp_rdma_component_ops); 235 236 return 0; 237 } 238 239 static const struct mtk_disp_rdma_data mt2701_rdma_driver_data = { 240 .fifo_size = SZ_4K, 241 }; 242 243 static const struct mtk_disp_rdma_data mt8173_rdma_driver_data = { 244 .fifo_size = SZ_8K, 245 }; 246 247 static const struct of_device_id mtk_disp_rdma_driver_dt_match[] = { 248 { .compatible = "mediatek,mt2701-disp-rdma", 249 .data = &mt2701_rdma_driver_data}, 250 { .compatible = "mediatek,mt8173-disp-rdma", 251 .data = &mt8173_rdma_driver_data}, 252 {}, 253 }; 254 MODULE_DEVICE_TABLE(of, mtk_disp_rdma_driver_dt_match); 255 256 struct platform_driver mtk_disp_rdma_driver = { 257 .probe = mtk_disp_rdma_probe, 258 .remove = mtk_disp_rdma_remove, 259 .driver = { 260 .name = "mediatek-disp-rdma", 261 .owner = THIS_MODULE, 262 .of_match_table = mtk_disp_rdma_driver_dt_match, 263 }, 264 }; 265