2 * Copyright (c) 2015 MediaTek Inc.
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.
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.
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>
21 #include "mtk_drm_crtc.h"
22 #include "mtk_drm_ddp_comp.h"
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)
43 struct mtk_disp_rdma_data
{
44 unsigned int fifo_size
;
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
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
;
58 static inline struct mtk_disp_rdma
*comp_to_rdma(struct mtk_ddp_comp
*comp
)
60 return container_of(comp
, struct mtk_disp_rdma
, ddp_comp
);
63 static irqreturn_t
mtk_disp_rdma_irq_handler(int irq
, void *dev_id
)
65 struct mtk_disp_rdma
*priv
= dev_id
;
66 struct mtk_ddp_comp
*rdma
= &priv
->ddp_comp
;
68 /* Clear frame completion interrupt */
69 writel(0x0, rdma
->regs
+ DISP_REG_RDMA_INT_STATUS
);
74 mtk_crtc_ddp_irq(priv
->crtc
, rdma
);
79 static void rdma_update_bits(struct mtk_ddp_comp
*comp
, unsigned int reg
,
80 unsigned int mask
, unsigned int val
)
82 unsigned int tmp
= readl(comp
->regs
+ reg
);
84 tmp
= (tmp
& ~mask
) | (val
& mask
);
85 writel(tmp
, comp
->regs
+ reg
);
88 static void mtk_rdma_enable_vblank(struct mtk_ddp_comp
*comp
,
89 struct drm_crtc
*crtc
)
91 struct mtk_disp_rdma
*rdma
= comp_to_rdma(comp
);
94 rdma_update_bits(comp
, DISP_REG_RDMA_INT_ENABLE
, RDMA_FRAME_END_INT
,
98 static void mtk_rdma_disable_vblank(struct mtk_ddp_comp
*comp
)
100 struct mtk_disp_rdma
*rdma
= comp_to_rdma(comp
);
103 rdma_update_bits(comp
, DISP_REG_RDMA_INT_ENABLE
, RDMA_FRAME_END_INT
, 0);
106 static void mtk_rdma_start(struct mtk_ddp_comp
*comp
)
108 rdma_update_bits(comp
, DISP_REG_RDMA_GLOBAL_CON
, RDMA_ENGINE_EN
,
112 static void mtk_rdma_stop(struct mtk_ddp_comp
*comp
)
114 rdma_update_bits(comp
, DISP_REG_RDMA_GLOBAL_CON
, RDMA_ENGINE_EN
, 0);
117 static void mtk_rdma_config(struct mtk_ddp_comp
*comp
, unsigned int width
,
118 unsigned int height
, unsigned int vrefresh
,
121 unsigned int threshold
;
123 struct mtk_disp_rdma
*rdma
= comp_to_rdma(comp
);
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
);
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:
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
);
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
,
149 static int mtk_disp_rdma_bind(struct device
*dev
, struct device
*master
,
152 struct mtk_disp_rdma
*priv
= dev_get_drvdata(dev
);
153 struct drm_device
*drm_dev
= data
;
156 ret
= mtk_ddp_comp_register(drm_dev
, &priv
->ddp_comp
);
158 dev_err(dev
, "Failed to register component %s: %d\n",
159 dev
->of_node
->full_name
, ret
);
167 static void mtk_disp_rdma_unbind(struct device
*dev
, struct device
*master
,
170 struct mtk_disp_rdma
*priv
= dev_get_drvdata(dev
);
171 struct drm_device
*drm_dev
= data
;
173 mtk_ddp_comp_unregister(drm_dev
, &priv
->ddp_comp
);
176 static const struct component_ops mtk_disp_rdma_component_ops
= {
177 .bind
= mtk_disp_rdma_bind
,
178 .unbind
= mtk_disp_rdma_unbind
,
181 static int mtk_disp_rdma_probe(struct platform_device
*pdev
)
183 struct device
*dev
= &pdev
->dev
;
184 struct mtk_disp_rdma
*priv
;
189 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
193 irq
= platform_get_irq(pdev
, 0);
197 comp_id
= mtk_ddp_comp_get_id(dev
->of_node
, MTK_DISP_RDMA
);
199 dev_err(dev
, "Failed to identify by alias: %d\n", comp_id
);
203 ret
= mtk_ddp_comp_init(dev
, dev
->of_node
, &priv
->ddp_comp
, comp_id
,
204 &mtk_disp_rdma_funcs
);
206 dev_err(dev
, "Failed to initialize component: %d\n", ret
);
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
);
214 ret
= devm_request_irq(dev
, irq
, mtk_disp_rdma_irq_handler
,
215 IRQF_TRIGGER_NONE
, dev_name(dev
), priv
);
217 dev_err(dev
, "Failed to request irq %d: %d\n", irq
, ret
);
221 priv
->data
= of_device_get_match_data(dev
);
223 platform_set_drvdata(pdev
, priv
);
225 ret
= component_add(dev
, &mtk_disp_rdma_component_ops
);
227 dev_err(dev
, "Failed to add component: %d\n", ret
);
232 static int mtk_disp_rdma_remove(struct platform_device
*pdev
)
234 component_del(&pdev
->dev
, &mtk_disp_rdma_component_ops
);
239 static const struct mtk_disp_rdma_data mt2701_rdma_driver_data
= {
243 static const struct mtk_disp_rdma_data mt8173_rdma_driver_data
= {
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
},
254 MODULE_DEVICE_TABLE(of
, mtk_disp_rdma_driver_dt_match
);
256 struct platform_driver mtk_disp_rdma_driver
= {
257 .probe
= mtk_disp_rdma_probe
,
258 .remove
= mtk_disp_rdma_remove
,
260 .name
= "mediatek-disp-rdma",
261 .owner
= THIS_MODULE
,
262 .of_match_table
= mtk_disp_rdma_driver_dt_match
,