Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2021 MediaTek Inc.
0004  */
0005 
0006 #include <linux/clk.h>
0007 #include <linux/component.h>
0008 #include <linux/of_device.h>
0009 #include <linux/of_irq.h>
0010 #include <linux/platform_device.h>
0011 #include <linux/reset.h>
0012 #include <linux/soc/mediatek/mtk-cmdq.h>
0013 
0014 #include "mtk_drm_ddp_comp.h"
0015 #include "mtk_drm_drv.h"
0016 #include "mtk_disp_drv.h"
0017 
0018 #define DISP_REG_MERGE_CTRL     0x000
0019 #define MERGE_EN                1
0020 #define DISP_REG_MERGE_CFG_0        0x010
0021 #define DISP_REG_MERGE_CFG_1        0x014
0022 #define DISP_REG_MERGE_CFG_4        0x020
0023 #define DISP_REG_MERGE_CFG_10       0x038
0024 /* no swap */
0025 #define SWAP_MODE               0
0026 #define FLD_SWAP_MODE               GENMASK(4, 0)
0027 #define DISP_REG_MERGE_CFG_12       0x040
0028 #define CFG_10_10_1PI_2PO_BUF_MODE      6
0029 #define CFG_10_10_2PI_2PO_BUF_MODE      8
0030 #define CFG_11_10_1PI_2PO_MERGE         18
0031 #define FLD_CFG_MERGE_MODE          GENMASK(4, 0)
0032 #define DISP_REG_MERGE_CFG_24       0x070
0033 #define DISP_REG_MERGE_CFG_25       0x074
0034 #define DISP_REG_MERGE_CFG_26       0x078
0035 #define DISP_REG_MERGE_CFG_27       0x07c
0036 #define DISP_REG_MERGE_CFG_36       0x0a0
0037 #define ULTRA_EN                BIT(0)
0038 #define PREULTRA_EN             BIT(4)
0039 #define DISP_REG_MERGE_CFG_37       0x0a4
0040 /* 0: Off, 1: SRAM0, 2: SRAM1, 3: SRAM0 + SRAM1 */
0041 #define BUFFER_MODE             3
0042 #define FLD_BUFFER_MODE             GENMASK(1, 0)
0043 /*
0044  * For the ultra and preultra settings, 6us ~ 9us is experience value
0045  * and the maximum frequency of mmsys clock is 594MHz.
0046  */
0047 #define DISP_REG_MERGE_CFG_40       0x0b0
0048 /* 6 us, 594M pixel/sec */
0049 #define ULTRA_TH_LOW                (6 * 594)
0050 /* 8 us, 594M pixel/sec */
0051 #define ULTRA_TH_HIGH               (8 * 594)
0052 #define FLD_ULTRA_TH_LOW            GENMASK(15, 0)
0053 #define FLD_ULTRA_TH_HIGH           GENMASK(31, 16)
0054 #define DISP_REG_MERGE_CFG_41       0x0b4
0055 /* 8 us, 594M pixel/sec */
0056 #define PREULTRA_TH_LOW             (8 * 594)
0057 /* 9 us, 594M pixel/sec */
0058 #define PREULTRA_TH_HIGH            (9 * 594)
0059 #define FLD_PREULTRA_TH_LOW         GENMASK(15, 0)
0060 #define FLD_PREULTRA_TH_HIGH            GENMASK(31, 16)
0061 
0062 #define DISP_REG_MERGE_MUTE_0       0xf00
0063 
0064 struct mtk_disp_merge {
0065     void __iomem            *regs;
0066     struct clk          *clk;
0067     struct clk          *async_clk;
0068     struct cmdq_client_reg      cmdq_reg;
0069     bool                fifo_en;
0070     bool                mute_support;
0071     struct reset_control        *reset_ctl;
0072 };
0073 
0074 void mtk_merge_start(struct device *dev)
0075 {
0076     mtk_merge_start_cmdq(dev, NULL);
0077 }
0078 
0079 void mtk_merge_stop(struct device *dev)
0080 {
0081     mtk_merge_stop_cmdq(dev, NULL);
0082 }
0083 
0084 void mtk_merge_start_cmdq(struct device *dev, struct cmdq_pkt *cmdq_pkt)
0085 {
0086     struct mtk_disp_merge *priv = dev_get_drvdata(dev);
0087 
0088     if (priv->mute_support)
0089         mtk_ddp_write(cmdq_pkt, 0x0, &priv->cmdq_reg, priv->regs,
0090                   DISP_REG_MERGE_MUTE_0);
0091 
0092     mtk_ddp_write(cmdq_pkt, 1, &priv->cmdq_reg, priv->regs,
0093               DISP_REG_MERGE_CTRL);
0094 }
0095 
0096 void mtk_merge_stop_cmdq(struct device *dev, struct cmdq_pkt *cmdq_pkt)
0097 {
0098     struct mtk_disp_merge *priv = dev_get_drvdata(dev);
0099 
0100     if (priv->mute_support)
0101         mtk_ddp_write(cmdq_pkt, 0x1, &priv->cmdq_reg, priv->regs,
0102                   DISP_REG_MERGE_MUTE_0);
0103 
0104     mtk_ddp_write(cmdq_pkt, 0, &priv->cmdq_reg, priv->regs,
0105               DISP_REG_MERGE_CTRL);
0106 
0107     if (priv->async_clk)
0108         reset_control_reset(priv->reset_ctl);
0109 }
0110 
0111 static void mtk_merge_fifo_setting(struct mtk_disp_merge *priv,
0112                    struct cmdq_pkt *cmdq_pkt)
0113 {
0114     mtk_ddp_write(cmdq_pkt, ULTRA_EN | PREULTRA_EN,
0115               &priv->cmdq_reg, priv->regs, DISP_REG_MERGE_CFG_36);
0116 
0117     mtk_ddp_write_mask(cmdq_pkt, BUFFER_MODE,
0118                &priv->cmdq_reg, priv->regs, DISP_REG_MERGE_CFG_37,
0119                FLD_BUFFER_MODE);
0120 
0121     mtk_ddp_write_mask(cmdq_pkt, ULTRA_TH_LOW | ULTRA_TH_HIGH << 16,
0122                &priv->cmdq_reg, priv->regs, DISP_REG_MERGE_CFG_40,
0123                FLD_ULTRA_TH_LOW | FLD_ULTRA_TH_HIGH);
0124 
0125     mtk_ddp_write_mask(cmdq_pkt, PREULTRA_TH_LOW | PREULTRA_TH_HIGH << 16,
0126                &priv->cmdq_reg, priv->regs, DISP_REG_MERGE_CFG_41,
0127                FLD_PREULTRA_TH_LOW | FLD_PREULTRA_TH_HIGH);
0128 }
0129 
0130 void mtk_merge_config(struct device *dev, unsigned int w,
0131               unsigned int h, unsigned int vrefresh,
0132               unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
0133 {
0134     mtk_merge_advance_config(dev, w, 0, h, vrefresh, bpc, cmdq_pkt);
0135 }
0136 
0137 void mtk_merge_advance_config(struct device *dev, unsigned int l_w, unsigned int r_w,
0138                   unsigned int h, unsigned int vrefresh, unsigned int bpc,
0139                   struct cmdq_pkt *cmdq_pkt)
0140 {
0141     struct mtk_disp_merge *priv = dev_get_drvdata(dev);
0142     unsigned int mode = CFG_10_10_1PI_2PO_BUF_MODE;
0143 
0144     if (!h || !l_w) {
0145         dev_err(dev, "%s: input width(%d) or height(%d) is invalid\n", __func__, l_w, h);
0146         return;
0147     }
0148 
0149     if (priv->fifo_en) {
0150         mtk_merge_fifo_setting(priv, cmdq_pkt);
0151         mode = CFG_10_10_2PI_2PO_BUF_MODE;
0152     }
0153 
0154     if (r_w)
0155         mode = CFG_11_10_1PI_2PO_MERGE;
0156 
0157     mtk_ddp_write(cmdq_pkt, h << 16 | l_w, &priv->cmdq_reg, priv->regs,
0158               DISP_REG_MERGE_CFG_0);
0159     mtk_ddp_write(cmdq_pkt, h << 16 | r_w, &priv->cmdq_reg, priv->regs,
0160               DISP_REG_MERGE_CFG_1);
0161     mtk_ddp_write(cmdq_pkt, h << 16 | (l_w + r_w), &priv->cmdq_reg, priv->regs,
0162               DISP_REG_MERGE_CFG_4);
0163     /*
0164      * DISP_REG_MERGE_CFG_24 is merge SRAM0 w/h
0165      * DISP_REG_MERGE_CFG_25 is merge SRAM1 w/h.
0166      * If r_w > 0, the merge is in merge mode (input0 and input1 merge together),
0167      * the input0 goes to SRAM0, and input1 goes to SRAM1.
0168      * If r_w = 0, the merge is in buffer mode, the input goes through SRAM0 and
0169      * then to SRAM1. Both SRAM0 and SRAM1 are set to the same size.
0170      */
0171     mtk_ddp_write(cmdq_pkt, h << 16 | l_w, &priv->cmdq_reg, priv->regs,
0172               DISP_REG_MERGE_CFG_24);
0173     if (r_w)
0174         mtk_ddp_write(cmdq_pkt, h << 16 | r_w, &priv->cmdq_reg, priv->regs,
0175                   DISP_REG_MERGE_CFG_25);
0176     else
0177         mtk_ddp_write(cmdq_pkt, h << 16 | l_w, &priv->cmdq_reg, priv->regs,
0178                   DISP_REG_MERGE_CFG_25);
0179 
0180     /*
0181      * DISP_REG_MERGE_CFG_26 and DISP_REG_MERGE_CFG_27 is only used in LR merge.
0182      * Only take effect when the merge is setting to merge mode.
0183      */
0184     mtk_ddp_write(cmdq_pkt, h << 16 | l_w, &priv->cmdq_reg, priv->regs,
0185               DISP_REG_MERGE_CFG_26);
0186     mtk_ddp_write(cmdq_pkt, h << 16 | r_w, &priv->cmdq_reg, priv->regs,
0187               DISP_REG_MERGE_CFG_27);
0188 
0189     mtk_ddp_write_mask(cmdq_pkt, SWAP_MODE, &priv->cmdq_reg, priv->regs,
0190                DISP_REG_MERGE_CFG_10, FLD_SWAP_MODE);
0191     mtk_ddp_write_mask(cmdq_pkt, mode, &priv->cmdq_reg, priv->regs,
0192                DISP_REG_MERGE_CFG_12, FLD_CFG_MERGE_MODE);
0193 }
0194 
0195 int mtk_merge_clk_enable(struct device *dev)
0196 {
0197     int ret = 0;
0198     struct mtk_disp_merge *priv = dev_get_drvdata(dev);
0199 
0200     ret = clk_prepare_enable(priv->clk);
0201     if (ret) {
0202         dev_err(dev, "merge clk prepare enable failed\n");
0203         return ret;
0204     }
0205 
0206     ret = clk_prepare_enable(priv->async_clk);
0207     if (ret) {
0208         /* should clean up the state of priv->clk */
0209         clk_disable_unprepare(priv->clk);
0210 
0211         dev_err(dev, "async clk prepare enable failed\n");
0212         return ret;
0213     }
0214 
0215     return ret;
0216 }
0217 
0218 void mtk_merge_clk_disable(struct device *dev)
0219 {
0220     struct mtk_disp_merge *priv = dev_get_drvdata(dev);
0221 
0222     clk_disable_unprepare(priv->async_clk);
0223     clk_disable_unprepare(priv->clk);
0224 }
0225 
0226 static int mtk_disp_merge_bind(struct device *dev, struct device *master,
0227                    void *data)
0228 {
0229     return 0;
0230 }
0231 
0232 static void mtk_disp_merge_unbind(struct device *dev, struct device *master,
0233                   void *data)
0234 {
0235 }
0236 
0237 static const struct component_ops mtk_disp_merge_component_ops = {
0238     .bind   = mtk_disp_merge_bind,
0239     .unbind = mtk_disp_merge_unbind,
0240 };
0241 
0242 static int mtk_disp_merge_probe(struct platform_device *pdev)
0243 {
0244     struct device *dev = &pdev->dev;
0245     struct resource *res;
0246     struct mtk_disp_merge *priv;
0247     int ret;
0248 
0249     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0250     if (!priv)
0251         return -ENOMEM;
0252 
0253     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0254     priv->regs = devm_ioremap_resource(dev, res);
0255     if (IS_ERR(priv->regs)) {
0256         dev_err(dev, "failed to ioremap merge\n");
0257         return PTR_ERR(priv->regs);
0258     }
0259 
0260     priv->clk = devm_clk_get(dev, NULL);
0261     if (IS_ERR(priv->clk)) {
0262         dev_err(dev, "failed to get merge clk\n");
0263         return PTR_ERR(priv->clk);
0264     }
0265 
0266     priv->async_clk = devm_clk_get_optional(dev, "merge_async");
0267     if (IS_ERR(priv->async_clk)) {
0268         dev_err(dev, "failed to get merge async clock\n");
0269         return PTR_ERR(priv->async_clk);
0270     }
0271 
0272     if (priv->async_clk) {
0273         priv->reset_ctl = devm_reset_control_get_optional_exclusive(dev, NULL);
0274         if (IS_ERR(priv->reset_ctl))
0275             return PTR_ERR(priv->reset_ctl);
0276     }
0277 
0278 #if IS_REACHABLE(CONFIG_MTK_CMDQ)
0279     ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
0280     if (ret)
0281         dev_dbg(dev, "get mediatek,gce-client-reg fail!\n");
0282 #endif
0283 
0284     priv->fifo_en = of_property_read_bool(dev->of_node,
0285                           "mediatek,merge-fifo-en");
0286 
0287     priv->mute_support = of_property_read_bool(dev->of_node,
0288                            "mediatek,merge-mute");
0289     platform_set_drvdata(pdev, priv);
0290 
0291     ret = component_add(dev, &mtk_disp_merge_component_ops);
0292     if (ret != 0)
0293         dev_err(dev, "Failed to add component: %d\n", ret);
0294 
0295     return ret;
0296 }
0297 
0298 static int mtk_disp_merge_remove(struct platform_device *pdev)
0299 {
0300     component_del(&pdev->dev, &mtk_disp_merge_component_ops);
0301 
0302     return 0;
0303 }
0304 
0305 static const struct of_device_id mtk_disp_merge_driver_dt_match[] = {
0306     { .compatible = "mediatek,mt8195-disp-merge", },
0307     {},
0308 };
0309 
0310 MODULE_DEVICE_TABLE(of, mtk_disp_merge_driver_dt_match);
0311 
0312 struct platform_driver mtk_disp_merge_driver = {
0313     .probe = mtk_disp_merge_probe,
0314     .remove = mtk_disp_merge_remove,
0315     .driver = {
0316         .name = "mediatek-disp-merge",
0317         .owner = THIS_MODULE,
0318         .of_match_table = mtk_disp_merge_driver_dt_match,
0319     },
0320 };