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