746 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2009 Nokia Corporation4 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>5 *6 * Some code and ideas taken from drivers/video/omap/ driver7 * by Imre Deak.8 */9 10#define DSS_SUBSYS_NAME "DPI"11 12#include <linux/clk.h>13#include <linux/delay.h>14#include <linux/err.h>15#include <linux/errno.h>16#include <linux/export.h>17#include <linux/kernel.h>18#include <linux/of.h>19#include <linux/platform_device.h>20#include <linux/regulator/consumer.h>21#include <linux/string.h>22#include <linux/sys_soc.h>23 24#include <drm/drm_bridge.h>25 26#include "dss.h"27#include "omapdss.h"28 29struct dpi_data {30 struct platform_device *pdev;31 enum dss_model dss_model;32 struct dss_device *dss;33 unsigned int id;34 35 struct regulator *vdds_dsi_reg;36 enum dss_clk_source clk_src;37 struct dss_pll *pll;38 39 struct dss_lcd_mgr_config mgr_config;40 unsigned long pixelclock;41 int data_lines;42 43 struct omap_dss_device output;44 struct drm_bridge bridge;45};46 47#define drm_bridge_to_dpi(bridge) container_of(bridge, struct dpi_data, bridge)48 49/* -----------------------------------------------------------------------------50 * Clock Handling and PLL51 */52 53static enum dss_clk_source dpi_get_clk_src_dra7xx(struct dpi_data *dpi,54 enum omap_channel channel)55{56 /*57 * Possible clock sources:58 * LCD1: FCK/PLL1_1/HDMI_PLL59 * LCD2: FCK/PLL1_3/HDMI_PLL (DRA74x: PLL2_3)60 * LCD3: FCK/PLL1_3/HDMI_PLL (DRA74x: PLL2_1)61 */62 63 switch (channel) {64 case OMAP_DSS_CHANNEL_LCD:65 {66 if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_1))67 return DSS_CLK_SRC_PLL1_1;68 break;69 }70 case OMAP_DSS_CHANNEL_LCD2:71 {72 if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_3))73 return DSS_CLK_SRC_PLL1_3;74 if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL2_3))75 return DSS_CLK_SRC_PLL2_3;76 break;77 }78 case OMAP_DSS_CHANNEL_LCD3:79 {80 if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL2_1))81 return DSS_CLK_SRC_PLL2_1;82 if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_3))83 return DSS_CLK_SRC_PLL1_3;84 break;85 }86 default:87 break;88 }89 90 return DSS_CLK_SRC_FCK;91}92 93static enum dss_clk_source dpi_get_clk_src(struct dpi_data *dpi)94{95 enum omap_channel channel = dpi->output.dispc_channel;96 97 /*98 * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL99 * would also be used for DISPC fclk. Meaning, when the DPI output is100 * disabled, DISPC clock will be disabled, and TV out will stop.101 */102 switch (dpi->dss_model) {103 case DSS_MODEL_OMAP2:104 case DSS_MODEL_OMAP3:105 return DSS_CLK_SRC_FCK;106 107 case DSS_MODEL_OMAP4:108 switch (channel) {109 case OMAP_DSS_CHANNEL_LCD:110 return DSS_CLK_SRC_PLL1_1;111 case OMAP_DSS_CHANNEL_LCD2:112 return DSS_CLK_SRC_PLL2_1;113 default:114 return DSS_CLK_SRC_FCK;115 }116 117 case DSS_MODEL_OMAP5:118 switch (channel) {119 case OMAP_DSS_CHANNEL_LCD:120 return DSS_CLK_SRC_PLL1_1;121 case OMAP_DSS_CHANNEL_LCD3:122 return DSS_CLK_SRC_PLL2_1;123 case OMAP_DSS_CHANNEL_LCD2:124 default:125 return DSS_CLK_SRC_FCK;126 }127 128 case DSS_MODEL_DRA7:129 return dpi_get_clk_src_dra7xx(dpi, channel);130 131 default:132 return DSS_CLK_SRC_FCK;133 }134}135 136struct dpi_clk_calc_ctx {137 struct dpi_data *dpi;138 unsigned int clkout_idx;139 140 /* inputs */141 142 unsigned long pck_min, pck_max;143 144 /* outputs */145 146 struct dss_pll_clock_info pll_cinfo;147 unsigned long fck;148 struct dispc_clock_info dispc_cinfo;149};150 151static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,152 unsigned long pck, void *data)153{154 struct dpi_clk_calc_ctx *ctx = data;155 156 /*157 * Odd dividers give us uneven duty cycle, causing problem when level158 * shifted. So skip all odd dividers when the pixel clock is on the159 * higher side.160 */161 if (ctx->pck_min >= 100000000) {162 if (lckd > 1 && lckd % 2 != 0)163 return false;164 165 if (pckd > 1 && pckd % 2 != 0)166 return false;167 }168 169 ctx->dispc_cinfo.lck_div = lckd;170 ctx->dispc_cinfo.pck_div = pckd;171 ctx->dispc_cinfo.lck = lck;172 ctx->dispc_cinfo.pck = pck;173 174 return true;175}176 177 178static bool dpi_calc_hsdiv_cb(int m_dispc, unsigned long dispc,179 void *data)180{181 struct dpi_clk_calc_ctx *ctx = data;182 183 ctx->pll_cinfo.mX[ctx->clkout_idx] = m_dispc;184 ctx->pll_cinfo.clkout[ctx->clkout_idx] = dispc;185 186 return dispc_div_calc(ctx->dpi->dss->dispc, dispc,187 ctx->pck_min, ctx->pck_max,188 dpi_calc_dispc_cb, ctx);189}190 191 192static bool dpi_calc_pll_cb(int n, int m, unsigned long fint,193 unsigned long clkdco,194 void *data)195{196 struct dpi_clk_calc_ctx *ctx = data;197 198 ctx->pll_cinfo.n = n;199 ctx->pll_cinfo.m = m;200 ctx->pll_cinfo.fint = fint;201 ctx->pll_cinfo.clkdco = clkdco;202 203 return dss_pll_hsdiv_calc_a(ctx->dpi->pll, clkdco,204 ctx->pck_min, dss_get_max_fck_rate(ctx->dpi->dss),205 dpi_calc_hsdiv_cb, ctx);206}207 208static bool dpi_calc_dss_cb(unsigned long fck, void *data)209{210 struct dpi_clk_calc_ctx *ctx = data;211 212 ctx->fck = fck;213 214 return dispc_div_calc(ctx->dpi->dss->dispc, fck,215 ctx->pck_min, ctx->pck_max,216 dpi_calc_dispc_cb, ctx);217}218 219static bool dpi_pll_clk_calc(struct dpi_data *dpi, unsigned long pck,220 struct dpi_clk_calc_ctx *ctx)221{222 unsigned long clkin;223 224 memset(ctx, 0, sizeof(*ctx));225 ctx->dpi = dpi;226 ctx->clkout_idx = dss_pll_get_clkout_idx_for_src(dpi->clk_src);227 228 clkin = clk_get_rate(dpi->pll->clkin);229 230 if (dpi->pll->hw->type == DSS_PLL_TYPE_A) {231 unsigned long pll_min, pll_max;232 233 ctx->pck_min = pck - 1000;234 ctx->pck_max = pck + 1000;235 236 pll_min = 0;237 pll_max = 0;238 239 return dss_pll_calc_a(ctx->dpi->pll, clkin,240 pll_min, pll_max,241 dpi_calc_pll_cb, ctx);242 } else { /* DSS_PLL_TYPE_B */243 dss_pll_calc_b(dpi->pll, clkin, pck, &ctx->pll_cinfo);244 245 ctx->dispc_cinfo.lck_div = 1;246 ctx->dispc_cinfo.pck_div = 1;247 ctx->dispc_cinfo.lck = ctx->pll_cinfo.clkout[0];248 ctx->dispc_cinfo.pck = ctx->dispc_cinfo.lck;249 250 return true;251 }252}253 254static bool dpi_dss_clk_calc(struct dpi_data *dpi, unsigned long pck,255 struct dpi_clk_calc_ctx *ctx)256{257 int i;258 259 /*260 * DSS fck gives us very few possibilities, so finding a good pixel261 * clock may not be possible. We try multiple times to find the clock,262 * each time widening the pixel clock range we look for, up to263 * +/- ~15MHz.264 */265 266 for (i = 0; i < 25; ++i) {267 bool ok;268 269 memset(ctx, 0, sizeof(*ctx));270 ctx->dpi = dpi;271 if (pck > 1000 * i * i * i)272 ctx->pck_min = max(pck - 1000 * i * i * i, 0lu);273 else274 ctx->pck_min = 0;275 ctx->pck_max = pck + 1000 * i * i * i;276 277 ok = dss_div_calc(dpi->dss, pck, ctx->pck_min,278 dpi_calc_dss_cb, ctx);279 if (ok)280 return ok;281 }282 283 return false;284}285 286 287 288static int dpi_set_pll_clk(struct dpi_data *dpi, unsigned long pck_req)289{290 struct dpi_clk_calc_ctx ctx;291 int r;292 bool ok;293 294 ok = dpi_pll_clk_calc(dpi, pck_req, &ctx);295 if (!ok)296 return -EINVAL;297 298 r = dss_pll_set_config(dpi->pll, &ctx.pll_cinfo);299 if (r)300 return r;301 302 dss_select_lcd_clk_source(dpi->dss, dpi->output.dispc_channel,303 dpi->clk_src);304 305 dpi->mgr_config.clock_info = ctx.dispc_cinfo;306 307 return 0;308}309 310static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req)311{312 struct dpi_clk_calc_ctx ctx;313 int r;314 bool ok;315 316 ok = dpi_dss_clk_calc(dpi, pck_req, &ctx);317 if (!ok)318 return -EINVAL;319 320 r = dss_set_fck_rate(dpi->dss, ctx.fck);321 if (r)322 return r;323 324 dpi->mgr_config.clock_info = ctx.dispc_cinfo;325 326 return 0;327}328 329static int dpi_set_mode(struct dpi_data *dpi)330{331 int r;332 333 if (dpi->pll)334 r = dpi_set_pll_clk(dpi, dpi->pixelclock);335 else336 r = dpi_set_dispc_clk(dpi, dpi->pixelclock);337 338 return r;339}340 341static void dpi_config_lcd_manager(struct dpi_data *dpi)342{343 dpi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;344 345 dpi->mgr_config.stallmode = false;346 dpi->mgr_config.fifohandcheck = false;347 348 dpi->mgr_config.video_port_width = dpi->data_lines;349 350 dpi->mgr_config.lcden_sig_polarity = 0;351 352 dss_mgr_set_lcd_config(&dpi->output, &dpi->mgr_config);353}354 355static int dpi_clock_update(struct dpi_data *dpi, unsigned long *clock)356{357 int lck_div, pck_div;358 unsigned long fck;359 struct dpi_clk_calc_ctx ctx;360 361 if (dpi->pll) {362 if (!dpi_pll_clk_calc(dpi, *clock, &ctx))363 return -EINVAL;364 365 fck = ctx.pll_cinfo.clkout[ctx.clkout_idx];366 } else {367 if (!dpi_dss_clk_calc(dpi, *clock, &ctx))368 return -EINVAL;369 370 fck = ctx.fck;371 }372 373 lck_div = ctx.dispc_cinfo.lck_div;374 pck_div = ctx.dispc_cinfo.pck_div;375 376 *clock = fck / lck_div / pck_div;377 378 return 0;379}380 381static int dpi_verify_pll(struct dss_pll *pll)382{383 int r;384 385 /* do initial setup with the PLL to see if it is operational */386 387 r = dss_pll_enable(pll);388 if (r)389 return r;390 391 dss_pll_disable(pll);392 393 return 0;394}395 396static void dpi_init_pll(struct dpi_data *dpi)397{398 struct dss_pll *pll;399 400 if (dpi->pll)401 return;402 403 dpi->clk_src = dpi_get_clk_src(dpi);404 405 pll = dss_pll_find_by_src(dpi->dss, dpi->clk_src);406 if (!pll)407 return;408 409 if (dpi_verify_pll(pll)) {410 DSSWARN("PLL not operational\n");411 return;412 }413 414 dpi->pll = pll;415}416 417/* -----------------------------------------------------------------------------418 * DRM Bridge Operations419 */420 421static int dpi_bridge_attach(struct drm_bridge *bridge,422 enum drm_bridge_attach_flags flags)423{424 struct dpi_data *dpi = drm_bridge_to_dpi(bridge);425 426 if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))427 return -EINVAL;428 429 dpi_init_pll(dpi);430 431 return drm_bridge_attach(bridge->encoder, dpi->output.next_bridge,432 bridge, flags);433}434 435static enum drm_mode_status436dpi_bridge_mode_valid(struct drm_bridge *bridge,437 const struct drm_display_info *info,438 const struct drm_display_mode *mode)439{440 struct dpi_data *dpi = drm_bridge_to_dpi(bridge);441 unsigned long clock = mode->clock * 1000;442 int ret;443 444 if (mode->hdisplay % 8 != 0)445 return MODE_BAD_WIDTH;446 447 if (mode->clock == 0)448 return MODE_NOCLOCK;449 450 ret = dpi_clock_update(dpi, &clock);451 if (ret < 0)452 return MODE_CLOCK_RANGE;453 454 return MODE_OK;455}456 457static bool dpi_bridge_mode_fixup(struct drm_bridge *bridge,458 const struct drm_display_mode *mode,459 struct drm_display_mode *adjusted_mode)460{461 struct dpi_data *dpi = drm_bridge_to_dpi(bridge);462 unsigned long clock = mode->clock * 1000;463 int ret;464 465 ret = dpi_clock_update(dpi, &clock);466 if (ret < 0)467 return false;468 469 adjusted_mode->clock = clock / 1000;470 471 return true;472}473 474static void dpi_bridge_mode_set(struct drm_bridge *bridge,475 const struct drm_display_mode *mode,476 const struct drm_display_mode *adjusted_mode)477{478 struct dpi_data *dpi = drm_bridge_to_dpi(bridge);479 480 dpi->pixelclock = adjusted_mode->clock * 1000;481}482 483static void dpi_bridge_enable(struct drm_bridge *bridge)484{485 struct dpi_data *dpi = drm_bridge_to_dpi(bridge);486 int r;487 488 if (dpi->vdds_dsi_reg) {489 r = regulator_enable(dpi->vdds_dsi_reg);490 if (r)491 return;492 }493 494 r = dispc_runtime_get(dpi->dss->dispc);495 if (r)496 goto err_get_dispc;497 498 r = dss_dpi_select_source(dpi->dss, dpi->id, dpi->output.dispc_channel);499 if (r)500 goto err_src_sel;501 502 if (dpi->pll) {503 r = dss_pll_enable(dpi->pll);504 if (r)505 goto err_pll_init;506 }507 508 r = dpi_set_mode(dpi);509 if (r)510 goto err_set_mode;511 512 dpi_config_lcd_manager(dpi);513 514 mdelay(2);515 516 r = dss_mgr_enable(&dpi->output);517 if (r)518 goto err_mgr_enable;519 520 return;521 522err_mgr_enable:523err_set_mode:524 if (dpi->pll)525 dss_pll_disable(dpi->pll);526err_pll_init:527err_src_sel:528 dispc_runtime_put(dpi->dss->dispc);529err_get_dispc:530 if (dpi->vdds_dsi_reg)531 regulator_disable(dpi->vdds_dsi_reg);532}533 534static void dpi_bridge_disable(struct drm_bridge *bridge)535{536 struct dpi_data *dpi = drm_bridge_to_dpi(bridge);537 538 dss_mgr_disable(&dpi->output);539 540 if (dpi->pll) {541 dss_select_lcd_clk_source(dpi->dss, dpi->output.dispc_channel,542 DSS_CLK_SRC_FCK);543 dss_pll_disable(dpi->pll);544 }545 546 dispc_runtime_put(dpi->dss->dispc);547 548 if (dpi->vdds_dsi_reg)549 regulator_disable(dpi->vdds_dsi_reg);550}551 552static const struct drm_bridge_funcs dpi_bridge_funcs = {553 .attach = dpi_bridge_attach,554 .mode_valid = dpi_bridge_mode_valid,555 .mode_fixup = dpi_bridge_mode_fixup,556 .mode_set = dpi_bridge_mode_set,557 .enable = dpi_bridge_enable,558 .disable = dpi_bridge_disable,559};560 561static void dpi_bridge_init(struct dpi_data *dpi)562{563 dpi->bridge.funcs = &dpi_bridge_funcs;564 dpi->bridge.of_node = dpi->pdev->dev.of_node;565 dpi->bridge.type = DRM_MODE_CONNECTOR_DPI;566 567 drm_bridge_add(&dpi->bridge);568}569 570static void dpi_bridge_cleanup(struct dpi_data *dpi)571{572 drm_bridge_remove(&dpi->bridge);573}574 575/* -----------------------------------------------------------------------------576 * Initialisation and Cleanup577 */578 579/*580 * Return a hardcoded channel for the DPI output. This should work for581 * current use cases, but this can be later expanded to either resolve582 * the channel in some more dynamic manner, or get the channel as a user583 * parameter.584 */585static enum omap_channel dpi_get_channel(struct dpi_data *dpi)586{587 switch (dpi->dss_model) {588 case DSS_MODEL_OMAP2:589 case DSS_MODEL_OMAP3:590 return OMAP_DSS_CHANNEL_LCD;591 592 case DSS_MODEL_DRA7:593 switch (dpi->id) {594 case 2:595 return OMAP_DSS_CHANNEL_LCD3;596 case 1:597 return OMAP_DSS_CHANNEL_LCD2;598 case 0:599 default:600 return OMAP_DSS_CHANNEL_LCD;601 }602 603 case DSS_MODEL_OMAP4:604 return OMAP_DSS_CHANNEL_LCD2;605 606 case DSS_MODEL_OMAP5:607 return OMAP_DSS_CHANNEL_LCD3;608 609 default:610 DSSWARN("unsupported DSS version\n");611 return OMAP_DSS_CHANNEL_LCD;612 }613}614 615static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)616{617 struct omap_dss_device *out = &dpi->output;618 u32 port_num = 0;619 int r;620 621 dpi_bridge_init(dpi);622 623 of_property_read_u32(port, "reg", &port_num);624 dpi->id = port_num <= 2 ? port_num : 0;625 626 switch (port_num) {627 case 2:628 out->name = "dpi.2";629 break;630 case 1:631 out->name = "dpi.1";632 break;633 case 0:634 default:635 out->name = "dpi.0";636 break;637 }638 639 out->dev = &dpi->pdev->dev;640 out->id = OMAP_DSS_OUTPUT_DPI;641 out->type = OMAP_DISPLAY_TYPE_DPI;642 out->dispc_channel = dpi_get_channel(dpi);643 out->of_port = port_num;644 645 r = omapdss_device_init_output(out, &dpi->bridge);646 if (r < 0) {647 dpi_bridge_cleanup(dpi);648 return r;649 }650 651 omapdss_device_register(out);652 653 return 0;654}655 656static void dpi_uninit_output_port(struct device_node *port)657{658 struct dpi_data *dpi = port->data;659 struct omap_dss_device *out = &dpi->output;660 661 omapdss_device_unregister(out);662 omapdss_device_cleanup_output(out);663 664 dpi_bridge_cleanup(dpi);665}666 667/* -----------------------------------------------------------------------------668 * Initialisation and Cleanup669 */670 671static const struct soc_device_attribute dpi_soc_devices[] = {672 { .machine = "OMAP3[456]*" },673 { .machine = "[AD]M37*" },674 { /* sentinel */ }675};676 677static int dpi_init_regulator(struct dpi_data *dpi)678{679 struct regulator *vdds_dsi;680 681 /*682 * The DPI uses the DSI VDDS on OMAP34xx, OMAP35xx, OMAP36xx, AM37xx and683 * DM37xx only.684 */685 if (!soc_device_match(dpi_soc_devices))686 return 0;687 688 vdds_dsi = devm_regulator_get(&dpi->pdev->dev, "vdds_dsi");689 if (IS_ERR(vdds_dsi)) {690 if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)691 DSSERR("can't get VDDS_DSI regulator\n");692 return PTR_ERR(vdds_dsi);693 }694 695 dpi->vdds_dsi_reg = vdds_dsi;696 697 return 0;698}699 700int dpi_init_port(struct dss_device *dss, struct platform_device *pdev,701 struct device_node *port, enum dss_model dss_model)702{703 struct dpi_data *dpi;704 struct device_node *ep;705 u32 datalines;706 int r;707 708 dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);709 if (!dpi)710 return -ENOMEM;711 712 ep = of_get_next_child(port, NULL);713 if (!ep)714 return 0;715 716 r = of_property_read_u32(ep, "data-lines", &datalines);717 of_node_put(ep);718 if (r) {719 DSSERR("failed to parse datalines\n");720 return r;721 }722 723 dpi->data_lines = datalines;724 725 dpi->pdev = pdev;726 dpi->dss_model = dss_model;727 dpi->dss = dss;728 port->data = dpi;729 730 r = dpi_init_regulator(dpi);731 if (r)732 return r;733 734 return dpi_init_output_port(dpi, port);735}736 737void dpi_uninit_port(struct device_node *port)738{739 struct dpi_data *dpi = port->data;740 741 if (!dpi)742 return;743 744 dpi_uninit_output_port(port);745}746