Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) STMicroelectronics SA 2014
0004  * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
0005  */
0006 
0007 #include <linux/clk.h>
0008 #include <linux/component.h>
0009 #include <linux/debugfs.h>
0010 #include <linux/module.h>
0011 #include <linux/of_gpio.h>
0012 #include <linux/platform_device.h>
0013 
0014 #include <drm/drm_atomic_helper.h>
0015 #include <drm/drm_bridge.h>
0016 #include <drm/drm_device.h>
0017 #include <drm/drm_panel.h>
0018 #include <drm/drm_print.h>
0019 #include <drm/drm_probe_helper.h>
0020 
0021 #include "sti_awg_utils.h"
0022 #include "sti_drv.h"
0023 #include "sti_mixer.h"
0024 
0025 /* DVO registers */
0026 #define DVO_AWG_DIGSYNC_CTRL      0x0000
0027 #define DVO_DOF_CFG               0x0004
0028 #define DVO_LUT_PROG_LOW          0x0008
0029 #define DVO_LUT_PROG_MID          0x000C
0030 #define DVO_LUT_PROG_HIGH         0x0010
0031 #define DVO_DIGSYNC_INSTR_I       0x0100
0032 
0033 #define DVO_AWG_CTRL_EN           BIT(0)
0034 #define DVO_AWG_FRAME_BASED_SYNC  BIT(2)
0035 
0036 #define DVO_DOF_EN_LOWBYTE        BIT(0)
0037 #define DVO_DOF_EN_MIDBYTE        BIT(1)
0038 #define DVO_DOF_EN_HIGHBYTE       BIT(2)
0039 #define DVO_DOF_EN                BIT(6)
0040 #define DVO_DOF_MOD_COUNT_SHIFT   8
0041 
0042 #define DVO_LUT_ZERO              0
0043 #define DVO_LUT_Y_G               1
0044 #define DVO_LUT_Y_G_DEL           2
0045 #define DVO_LUT_CB_B              3
0046 #define DVO_LUT_CB_B_DEL          4
0047 #define DVO_LUT_CR_R              5
0048 #define DVO_LUT_CR_R_DEL          6
0049 #define DVO_LUT_HOLD              7
0050 
0051 struct dvo_config {
0052     u32 flags;
0053     u32 lowbyte;
0054     u32 midbyte;
0055     u32 highbyte;
0056     int (*awg_fwgen_fct)(
0057             struct awg_code_generation_params *fw_gen_params,
0058             struct awg_timing *timing);
0059 };
0060 
0061 static struct dvo_config rgb_24bit_de_cfg = {
0062     .flags         = (0L << DVO_DOF_MOD_COUNT_SHIFT),
0063     .lowbyte       = DVO_LUT_CR_R,
0064     .midbyte       = DVO_LUT_Y_G,
0065     .highbyte      = DVO_LUT_CB_B,
0066     .awg_fwgen_fct = sti_awg_generate_code_data_enable_mode,
0067 };
0068 
0069 /*
0070  * STI digital video output structure
0071  *
0072  * @dev: driver device
0073  * @drm_dev: pointer to drm device
0074  * @mode: current display mode selected
0075  * @regs: dvo registers
0076  * @clk_pix: pixel clock for dvo
0077  * @clk: clock for dvo
0078  * @clk_main_parent: dvo parent clock if main path used
0079  * @clk_aux_parent: dvo parent clock if aux path used
0080  * @panel_node: panel node reference from device tree
0081  * @panel: reference to the panel connected to the dvo
0082  * @enabled: true if dvo is enabled else false
0083  * @encoder: drm_encoder it is bound
0084  */
0085 struct sti_dvo {
0086     struct device dev;
0087     struct drm_device *drm_dev;
0088     struct drm_display_mode mode;
0089     void __iomem *regs;
0090     struct clk *clk_pix;
0091     struct clk *clk;
0092     struct clk *clk_main_parent;
0093     struct clk *clk_aux_parent;
0094     struct device_node *panel_node;
0095     struct drm_panel *panel;
0096     struct dvo_config *config;
0097     bool enabled;
0098     struct drm_encoder *encoder;
0099     struct drm_bridge *bridge;
0100 };
0101 
0102 struct sti_dvo_connector {
0103     struct drm_connector drm_connector;
0104     struct drm_encoder *encoder;
0105     struct sti_dvo *dvo;
0106 };
0107 
0108 #define to_sti_dvo_connector(x) \
0109     container_of(x, struct sti_dvo_connector, drm_connector)
0110 
0111 #define BLANKING_LEVEL 16
0112 static int dvo_awg_generate_code(struct sti_dvo *dvo, u8 *ram_size, u32 *ram_code)
0113 {
0114     struct drm_display_mode *mode = &dvo->mode;
0115     struct dvo_config *config = dvo->config;
0116     struct awg_code_generation_params fw_gen_params;
0117     struct awg_timing timing;
0118 
0119     fw_gen_params.ram_code = ram_code;
0120     fw_gen_params.instruction_offset = 0;
0121 
0122     timing.total_lines = mode->vtotal;
0123     timing.active_lines = mode->vdisplay;
0124     timing.blanking_lines = mode->vsync_start - mode->vdisplay;
0125     timing.trailing_lines = mode->vtotal - mode->vsync_start;
0126     timing.total_pixels = mode->htotal;
0127     timing.active_pixels = mode->hdisplay;
0128     timing.blanking_pixels = mode->hsync_start - mode->hdisplay;
0129     timing.trailing_pixels = mode->htotal - mode->hsync_start;
0130     timing.blanking_level = BLANKING_LEVEL;
0131 
0132     if (config->awg_fwgen_fct(&fw_gen_params, &timing)) {
0133         DRM_ERROR("AWG firmware not properly generated\n");
0134         return -EINVAL;
0135     }
0136 
0137     *ram_size = fw_gen_params.instruction_offset;
0138 
0139     return 0;
0140 }
0141 
0142 /* Configure AWG, writing instructions
0143  *
0144  * @dvo: pointer to DVO structure
0145  * @awg_ram_code: pointer to AWG instructions table
0146  * @nb: nb of AWG instructions
0147  */
0148 static void dvo_awg_configure(struct sti_dvo *dvo, u32 *awg_ram_code, int nb)
0149 {
0150     int i;
0151 
0152     DRM_DEBUG_DRIVER("\n");
0153 
0154     for (i = 0; i < nb; i++)
0155         writel(awg_ram_code[i],
0156                dvo->regs + DVO_DIGSYNC_INSTR_I + i * 4);
0157     for (i = nb; i < AWG_MAX_INST; i++)
0158         writel(0, dvo->regs + DVO_DIGSYNC_INSTR_I + i * 4);
0159 
0160     writel(DVO_AWG_CTRL_EN, dvo->regs + DVO_AWG_DIGSYNC_CTRL);
0161 }
0162 
0163 #define DBGFS_DUMP(reg) seq_printf(s, "\n  %-25s 0x%08X", #reg, \
0164                    readl(dvo->regs + reg))
0165 
0166 static void dvo_dbg_awg_microcode(struct seq_file *s, void __iomem *reg)
0167 {
0168     unsigned int i;
0169 
0170     seq_puts(s, "\n\n");
0171     seq_puts(s, "  DVO AWG microcode:");
0172     for (i = 0; i < AWG_MAX_INST; i++) {
0173         if (i % 8 == 0)
0174             seq_printf(s, "\n  %04X:", i);
0175         seq_printf(s, " %04X", readl(reg + i * 4));
0176     }
0177 }
0178 
0179 static int dvo_dbg_show(struct seq_file *s, void *data)
0180 {
0181     struct drm_info_node *node = s->private;
0182     struct sti_dvo *dvo = (struct sti_dvo *)node->info_ent->data;
0183 
0184     seq_printf(s, "DVO: (vaddr = 0x%p)", dvo->regs);
0185     DBGFS_DUMP(DVO_AWG_DIGSYNC_CTRL);
0186     DBGFS_DUMP(DVO_DOF_CFG);
0187     DBGFS_DUMP(DVO_LUT_PROG_LOW);
0188     DBGFS_DUMP(DVO_LUT_PROG_MID);
0189     DBGFS_DUMP(DVO_LUT_PROG_HIGH);
0190     dvo_dbg_awg_microcode(s, dvo->regs + DVO_DIGSYNC_INSTR_I);
0191     seq_putc(s, '\n');
0192     return 0;
0193 }
0194 
0195 static struct drm_info_list dvo_debugfs_files[] = {
0196     { "dvo", dvo_dbg_show, 0, NULL },
0197 };
0198 
0199 static void dvo_debugfs_init(struct sti_dvo *dvo, struct drm_minor *minor)
0200 {
0201     unsigned int i;
0202 
0203     for (i = 0; i < ARRAY_SIZE(dvo_debugfs_files); i++)
0204         dvo_debugfs_files[i].data = dvo;
0205 
0206     drm_debugfs_create_files(dvo_debugfs_files,
0207                  ARRAY_SIZE(dvo_debugfs_files),
0208                  minor->debugfs_root, minor);
0209 }
0210 
0211 static void sti_dvo_disable(struct drm_bridge *bridge)
0212 {
0213     struct sti_dvo *dvo = bridge->driver_private;
0214 
0215     if (!dvo->enabled)
0216         return;
0217 
0218     DRM_DEBUG_DRIVER("\n");
0219 
0220     if (dvo->config->awg_fwgen_fct)
0221         writel(0x00000000, dvo->regs + DVO_AWG_DIGSYNC_CTRL);
0222 
0223     writel(0x00000000, dvo->regs + DVO_DOF_CFG);
0224 
0225     drm_panel_disable(dvo->panel);
0226 
0227     /* Disable/unprepare dvo clock */
0228     clk_disable_unprepare(dvo->clk_pix);
0229     clk_disable_unprepare(dvo->clk);
0230 
0231     dvo->enabled = false;
0232 }
0233 
0234 static void sti_dvo_pre_enable(struct drm_bridge *bridge)
0235 {
0236     struct sti_dvo *dvo = bridge->driver_private;
0237     struct dvo_config *config = dvo->config;
0238     u32 val;
0239 
0240     DRM_DEBUG_DRIVER("\n");
0241 
0242     if (dvo->enabled)
0243         return;
0244 
0245     /* Make sure DVO is disabled */
0246     writel(0x00000000, dvo->regs + DVO_DOF_CFG);
0247     writel(0x00000000, dvo->regs + DVO_AWG_DIGSYNC_CTRL);
0248 
0249     if (config->awg_fwgen_fct) {
0250         u8 nb_instr;
0251         u32 awg_ram_code[AWG_MAX_INST];
0252         /* Configure AWG */
0253         if (!dvo_awg_generate_code(dvo, &nb_instr, awg_ram_code))
0254             dvo_awg_configure(dvo, awg_ram_code, nb_instr);
0255         else
0256             return;
0257     }
0258 
0259     /* Prepare/enable clocks */
0260     if (clk_prepare_enable(dvo->clk_pix))
0261         DRM_ERROR("Failed to prepare/enable dvo_pix clk\n");
0262     if (clk_prepare_enable(dvo->clk))
0263         DRM_ERROR("Failed to prepare/enable dvo clk\n");
0264 
0265     drm_panel_enable(dvo->panel);
0266 
0267     /* Set LUT */
0268     writel(config->lowbyte,  dvo->regs + DVO_LUT_PROG_LOW);
0269     writel(config->midbyte,  dvo->regs + DVO_LUT_PROG_MID);
0270     writel(config->highbyte, dvo->regs + DVO_LUT_PROG_HIGH);
0271 
0272     /* Digital output formatter config */
0273     val = (config->flags | DVO_DOF_EN);
0274     writel(val, dvo->regs + DVO_DOF_CFG);
0275 
0276     dvo->enabled = true;
0277 }
0278 
0279 static void sti_dvo_set_mode(struct drm_bridge *bridge,
0280                  const struct drm_display_mode *mode,
0281                  const struct drm_display_mode *adjusted_mode)
0282 {
0283     struct sti_dvo *dvo = bridge->driver_private;
0284     struct sti_mixer *mixer = to_sti_mixer(dvo->encoder->crtc);
0285     int rate = mode->clock * 1000;
0286     struct clk *clkp;
0287     int ret;
0288 
0289     DRM_DEBUG_DRIVER("\n");
0290 
0291     memcpy(&dvo->mode, mode, sizeof(struct drm_display_mode));
0292 
0293     /* According to the path used (main or aux), the dvo clocks should
0294      * have a different parent clock. */
0295     if (mixer->id == STI_MIXER_MAIN)
0296         clkp = dvo->clk_main_parent;
0297     else
0298         clkp = dvo->clk_aux_parent;
0299 
0300     if (clkp) {
0301         clk_set_parent(dvo->clk_pix, clkp);
0302         clk_set_parent(dvo->clk, clkp);
0303     }
0304 
0305     /* DVO clocks = compositor clock */
0306     ret = clk_set_rate(dvo->clk_pix, rate);
0307     if (ret < 0) {
0308         DRM_ERROR("Cannot set rate (%dHz) for dvo_pix clk\n", rate);
0309         return;
0310     }
0311 
0312     ret = clk_set_rate(dvo->clk, rate);
0313     if (ret < 0) {
0314         DRM_ERROR("Cannot set rate (%dHz) for dvo clk\n", rate);
0315         return;
0316     }
0317 
0318     /* For now, we only support 24bit data enable (DE) synchro format */
0319     dvo->config = &rgb_24bit_de_cfg;
0320 }
0321 
0322 static void sti_dvo_bridge_nope(struct drm_bridge *bridge)
0323 {
0324     /* do nothing */
0325 }
0326 
0327 static const struct drm_bridge_funcs sti_dvo_bridge_funcs = {
0328     .pre_enable = sti_dvo_pre_enable,
0329     .enable = sti_dvo_bridge_nope,
0330     .disable = sti_dvo_disable,
0331     .post_disable = sti_dvo_bridge_nope,
0332     .mode_set = sti_dvo_set_mode,
0333 };
0334 
0335 static int sti_dvo_connector_get_modes(struct drm_connector *connector)
0336 {
0337     struct sti_dvo_connector *dvo_connector
0338         = to_sti_dvo_connector(connector);
0339     struct sti_dvo *dvo = dvo_connector->dvo;
0340 
0341     if (dvo->panel)
0342         return drm_panel_get_modes(dvo->panel, connector);
0343 
0344     return 0;
0345 }
0346 
0347 #define CLK_TOLERANCE_HZ 50
0348 
0349 static int sti_dvo_connector_mode_valid(struct drm_connector *connector,
0350                     struct drm_display_mode *mode)
0351 {
0352     int target = mode->clock * 1000;
0353     int target_min = target - CLK_TOLERANCE_HZ;
0354     int target_max = target + CLK_TOLERANCE_HZ;
0355     int result;
0356     struct sti_dvo_connector *dvo_connector
0357         = to_sti_dvo_connector(connector);
0358     struct sti_dvo *dvo = dvo_connector->dvo;
0359 
0360     result = clk_round_rate(dvo->clk_pix, target);
0361 
0362     DRM_DEBUG_DRIVER("target rate = %d => available rate = %d\n",
0363              target, result);
0364 
0365     if ((result < target_min) || (result > target_max)) {
0366         DRM_DEBUG_DRIVER("dvo pixclk=%d not supported\n", target);
0367         return MODE_BAD;
0368     }
0369 
0370     return MODE_OK;
0371 }
0372 
0373 static const
0374 struct drm_connector_helper_funcs sti_dvo_connector_helper_funcs = {
0375     .get_modes = sti_dvo_connector_get_modes,
0376     .mode_valid = sti_dvo_connector_mode_valid,
0377 };
0378 
0379 static enum drm_connector_status
0380 sti_dvo_connector_detect(struct drm_connector *connector, bool force)
0381 {
0382     struct sti_dvo_connector *dvo_connector
0383         = to_sti_dvo_connector(connector);
0384     struct sti_dvo *dvo = dvo_connector->dvo;
0385 
0386     DRM_DEBUG_DRIVER("\n");
0387 
0388     if (!dvo->panel) {
0389         dvo->panel = of_drm_find_panel(dvo->panel_node);
0390         if (IS_ERR(dvo->panel))
0391             dvo->panel = NULL;
0392     }
0393 
0394     if (dvo->panel)
0395         return connector_status_connected;
0396 
0397     return connector_status_disconnected;
0398 }
0399 
0400 static int sti_dvo_late_register(struct drm_connector *connector)
0401 {
0402     struct sti_dvo_connector *dvo_connector
0403         = to_sti_dvo_connector(connector);
0404     struct sti_dvo *dvo = dvo_connector->dvo;
0405 
0406     dvo_debugfs_init(dvo, dvo->drm_dev->primary);
0407 
0408     return 0;
0409 }
0410 
0411 static const struct drm_connector_funcs sti_dvo_connector_funcs = {
0412     .fill_modes = drm_helper_probe_single_connector_modes,
0413     .detect = sti_dvo_connector_detect,
0414     .destroy = drm_connector_cleanup,
0415     .reset = drm_atomic_helper_connector_reset,
0416     .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
0417     .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
0418     .late_register = sti_dvo_late_register,
0419 };
0420 
0421 static struct drm_encoder *sti_dvo_find_encoder(struct drm_device *dev)
0422 {
0423     struct drm_encoder *encoder;
0424 
0425     list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
0426         if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS)
0427             return encoder;
0428     }
0429 
0430     return NULL;
0431 }
0432 
0433 static int sti_dvo_bind(struct device *dev, struct device *master, void *data)
0434 {
0435     struct sti_dvo *dvo = dev_get_drvdata(dev);
0436     struct drm_device *drm_dev = data;
0437     struct drm_encoder *encoder;
0438     struct sti_dvo_connector *connector;
0439     struct drm_connector *drm_connector;
0440     struct drm_bridge *bridge;
0441     int err;
0442 
0443     /* Set the drm device handle */
0444     dvo->drm_dev = drm_dev;
0445 
0446     encoder = sti_dvo_find_encoder(drm_dev);
0447     if (!encoder)
0448         return -ENOMEM;
0449 
0450     connector = devm_kzalloc(dev, sizeof(*connector), GFP_KERNEL);
0451     if (!connector)
0452         return -ENOMEM;
0453 
0454     connector->dvo = dvo;
0455 
0456     bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
0457     if (!bridge)
0458         return -ENOMEM;
0459 
0460     bridge->driver_private = dvo;
0461     bridge->funcs = &sti_dvo_bridge_funcs;
0462     bridge->of_node = dvo->dev.of_node;
0463     drm_bridge_add(bridge);
0464 
0465     err = drm_bridge_attach(encoder, bridge, NULL, 0);
0466     if (err)
0467         return err;
0468 
0469     dvo->bridge = bridge;
0470     connector->encoder = encoder;
0471     dvo->encoder = encoder;
0472 
0473     drm_connector = (struct drm_connector *)connector;
0474 
0475     drm_connector->polled = DRM_CONNECTOR_POLL_HPD;
0476 
0477     drm_connector_init(drm_dev, drm_connector,
0478                &sti_dvo_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
0479     drm_connector_helper_add(drm_connector,
0480                  &sti_dvo_connector_helper_funcs);
0481 
0482     err = drm_connector_attach_encoder(drm_connector, encoder);
0483     if (err) {
0484         DRM_ERROR("Failed to attach a connector to a encoder\n");
0485         goto err_sysfs;
0486     }
0487 
0488     return 0;
0489 
0490 err_sysfs:
0491     drm_bridge_remove(bridge);
0492     return -EINVAL;
0493 }
0494 
0495 static void sti_dvo_unbind(struct device *dev,
0496                struct device *master, void *data)
0497 {
0498     struct sti_dvo *dvo = dev_get_drvdata(dev);
0499 
0500     drm_bridge_remove(dvo->bridge);
0501 }
0502 
0503 static const struct component_ops sti_dvo_ops = {
0504     .bind = sti_dvo_bind,
0505     .unbind = sti_dvo_unbind,
0506 };
0507 
0508 static int sti_dvo_probe(struct platform_device *pdev)
0509 {
0510     struct device *dev = &pdev->dev;
0511     struct sti_dvo *dvo;
0512     struct resource *res;
0513     struct device_node *np = dev->of_node;
0514 
0515     DRM_INFO("%s\n", __func__);
0516 
0517     dvo = devm_kzalloc(dev, sizeof(*dvo), GFP_KERNEL);
0518     if (!dvo) {
0519         DRM_ERROR("Failed to allocate memory for DVO\n");
0520         return -ENOMEM;
0521     }
0522 
0523     dvo->dev = pdev->dev;
0524 
0525     res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dvo-reg");
0526     if (!res) {
0527         DRM_ERROR("Invalid dvo resource\n");
0528         return -ENOMEM;
0529     }
0530     dvo->regs = devm_ioremap(dev, res->start,
0531             resource_size(res));
0532     if (!dvo->regs)
0533         return -ENOMEM;
0534 
0535     dvo->clk_pix = devm_clk_get(dev, "dvo_pix");
0536     if (IS_ERR(dvo->clk_pix)) {
0537         DRM_ERROR("Cannot get dvo_pix clock\n");
0538         return PTR_ERR(dvo->clk_pix);
0539     }
0540 
0541     dvo->clk = devm_clk_get(dev, "dvo");
0542     if (IS_ERR(dvo->clk)) {
0543         DRM_ERROR("Cannot get dvo clock\n");
0544         return PTR_ERR(dvo->clk);
0545     }
0546 
0547     dvo->clk_main_parent = devm_clk_get(dev, "main_parent");
0548     if (IS_ERR(dvo->clk_main_parent)) {
0549         DRM_DEBUG_DRIVER("Cannot get main_parent clock\n");
0550         dvo->clk_main_parent = NULL;
0551     }
0552 
0553     dvo->clk_aux_parent = devm_clk_get(dev, "aux_parent");
0554     if (IS_ERR(dvo->clk_aux_parent)) {
0555         DRM_DEBUG_DRIVER("Cannot get aux_parent clock\n");
0556         dvo->clk_aux_parent = NULL;
0557     }
0558 
0559     dvo->panel_node = of_parse_phandle(np, "sti,panel", 0);
0560     if (!dvo->panel_node)
0561         DRM_ERROR("No panel associated to the dvo output\n");
0562     of_node_put(dvo->panel_node);
0563 
0564     platform_set_drvdata(pdev, dvo);
0565 
0566     return component_add(&pdev->dev, &sti_dvo_ops);
0567 }
0568 
0569 static int sti_dvo_remove(struct platform_device *pdev)
0570 {
0571     component_del(&pdev->dev, &sti_dvo_ops);
0572     return 0;
0573 }
0574 
0575 static const struct of_device_id dvo_of_match[] = {
0576     { .compatible = "st,stih407-dvo", },
0577     { /* end node */ }
0578 };
0579 MODULE_DEVICE_TABLE(of, dvo_of_match);
0580 
0581 struct platform_driver sti_dvo_driver = {
0582     .driver = {
0583         .name = "sti-dvo",
0584         .owner = THIS_MODULE,
0585         .of_match_table = dvo_of_match,
0586     },
0587     .probe = sti_dvo_probe,
0588     .remove = sti_dvo_remove,
0589 };
0590 
0591 MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
0592 MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
0593 MODULE_LICENSE("GPL");