1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2017 MediaTek Inc. 4 */ 5 6 #include <linux/clk.h> 7 #include <linux/component.h> 8 #include <linux/module.h> 9 #include <linux/of_device.h> 10 #include <linux/of_irq.h> 11 #include <linux/platform_device.h> 12 #include <linux/soc/mediatek/mtk-cmdq.h> 13 14 #include "mtk_drm_crtc.h" 15 #include "mtk_drm_ddp_comp.h" 16 17 #define DISP_COLOR_CFG_MAIN 0x0400 18 #define DISP_COLOR_START_MT2701 0x0f00 19 #define DISP_COLOR_START_MT8167 0x0400 20 #define DISP_COLOR_START_MT8173 0x0c00 21 #define DISP_COLOR_START(comp) ((comp)->data->color_offset) 22 #define DISP_COLOR_WIDTH(comp) (DISP_COLOR_START(comp) + 0x50) 23 #define DISP_COLOR_HEIGHT(comp) (DISP_COLOR_START(comp) + 0x54) 24 25 #define COLOR_BYPASS_ALL BIT(7) 26 #define COLOR_SEQ_SEL BIT(13) 27 28 struct mtk_disp_color_data { 29 unsigned int color_offset; 30 }; 31 32 /** 33 * struct mtk_disp_color - DISP_COLOR driver structure 34 * @ddp_comp: structure containing type enum and hardware resources 35 * @crtc: associated crtc to report irq events to 36 * @data: platform colour driver data 37 */ 38 struct mtk_disp_color { 39 struct mtk_ddp_comp ddp_comp; 40 struct drm_crtc *crtc; 41 const struct mtk_disp_color_data *data; 42 }; 43 44 static inline struct mtk_disp_color *comp_to_color(struct mtk_ddp_comp *comp) 45 { 46 return container_of(comp, struct mtk_disp_color, ddp_comp); 47 } 48 49 static void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w, 50 unsigned int h, unsigned int vrefresh, 51 unsigned int bpc, struct cmdq_pkt *cmdq_pkt) 52 { 53 struct mtk_disp_color *color = comp_to_color(comp); 54 55 mtk_ddp_write(cmdq_pkt, w, comp, DISP_COLOR_WIDTH(color)); 56 mtk_ddp_write(cmdq_pkt, h, comp, DISP_COLOR_HEIGHT(color)); 57 } 58 59 static void mtk_color_start(struct mtk_ddp_comp *comp) 60 { 61 struct mtk_disp_color *color = comp_to_color(comp); 62 63 writel(COLOR_BYPASS_ALL | COLOR_SEQ_SEL, 64 comp->regs + DISP_COLOR_CFG_MAIN); 65 writel(0x1, comp->regs + DISP_COLOR_START(color)); 66 } 67 68 static const struct mtk_ddp_comp_funcs mtk_disp_color_funcs = { 69 .config = mtk_color_config, 70 .start = mtk_color_start, 71 }; 72 73 static int mtk_disp_color_bind(struct device *dev, struct device *master, 74 void *data) 75 { 76 struct mtk_disp_color *priv = dev_get_drvdata(dev); 77 struct drm_device *drm_dev = data; 78 int ret; 79 80 ret = mtk_ddp_comp_register(drm_dev, &priv->ddp_comp); 81 if (ret < 0) { 82 dev_err(dev, "Failed to register component %pOF: %d\n", 83 dev->of_node, ret); 84 return ret; 85 } 86 87 return 0; 88 } 89 90 static void mtk_disp_color_unbind(struct device *dev, struct device *master, 91 void *data) 92 { 93 struct mtk_disp_color *priv = dev_get_drvdata(dev); 94 struct drm_device *drm_dev = data; 95 96 mtk_ddp_comp_unregister(drm_dev, &priv->ddp_comp); 97 } 98 99 static const struct component_ops mtk_disp_color_component_ops = { 100 .bind = mtk_disp_color_bind, 101 .unbind = mtk_disp_color_unbind, 102 }; 103 104 static int mtk_disp_color_probe(struct platform_device *pdev) 105 { 106 struct device *dev = &pdev->dev; 107 struct mtk_disp_color *priv; 108 int comp_id; 109 int ret; 110 111 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 112 if (!priv) 113 return -ENOMEM; 114 115 comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DISP_COLOR); 116 if (comp_id < 0) { 117 dev_err(dev, "Failed to identify by alias: %d\n", comp_id); 118 return comp_id; 119 } 120 121 ret = mtk_ddp_comp_init(dev, dev->of_node, &priv->ddp_comp, comp_id, 122 &mtk_disp_color_funcs); 123 if (ret) { 124 if (ret != -EPROBE_DEFER) 125 dev_err(dev, "Failed to initialize component: %d\n", 126 ret); 127 128 return ret; 129 } 130 131 priv->data = of_device_get_match_data(dev); 132 133 platform_set_drvdata(pdev, priv); 134 135 ret = component_add(dev, &mtk_disp_color_component_ops); 136 if (ret) 137 dev_err(dev, "Failed to add component: %d\n", ret); 138 139 return ret; 140 } 141 142 static int mtk_disp_color_remove(struct platform_device *pdev) 143 { 144 component_del(&pdev->dev, &mtk_disp_color_component_ops); 145 146 return 0; 147 } 148 149 static const struct mtk_disp_color_data mt2701_color_driver_data = { 150 .color_offset = DISP_COLOR_START_MT2701, 151 }; 152 153 static const struct mtk_disp_color_data mt8167_color_driver_data = { 154 .color_offset = DISP_COLOR_START_MT8167, 155 }; 156 157 static const struct mtk_disp_color_data mt8173_color_driver_data = { 158 .color_offset = DISP_COLOR_START_MT8173, 159 }; 160 161 static const struct of_device_id mtk_disp_color_driver_dt_match[] = { 162 { .compatible = "mediatek,mt2701-disp-color", 163 .data = &mt2701_color_driver_data}, 164 { .compatible = "mediatek,mt8167-disp-color", 165 .data = &mt8167_color_driver_data}, 166 { .compatible = "mediatek,mt8173-disp-color", 167 .data = &mt8173_color_driver_data}, 168 {}, 169 }; 170 MODULE_DEVICE_TABLE(of, mtk_disp_color_driver_dt_match); 171 172 struct platform_driver mtk_disp_color_driver = { 173 .probe = mtk_disp_color_probe, 174 .remove = mtk_disp_color_remove, 175 .driver = { 176 .name = "mediatek-disp-color", 177 .owner = THIS_MODULE, 178 .of_match_table = mtk_disp_color_driver_dt_match, 179 }, 180 }; 181