.. | .. |
---|
9 | 9 | #include <linux/gpio/consumer.h> |
---|
10 | 10 | #include <linux/i2c.h> |
---|
11 | 11 | #include <linux/kernel.h> |
---|
| 12 | +#include <linux/media-bus-format.h> |
---|
| 13 | +#include <linux/minmax.h> |
---|
12 | 14 | #include <linux/module.h> |
---|
13 | 15 | #include <linux/regmap.h> |
---|
14 | 16 | #include <linux/regulator/consumer.h> |
---|
.. | .. |
---|
147 | 149 | |
---|
148 | 150 | u32 pd_lines; /* number of Parallel Port Input Data Lines */ |
---|
149 | 151 | u32 dsi_lanes; /* number of DSI Lanes */ |
---|
| 152 | + u32 dsi_bpp; /* number of Bits Per Pixel over DSI */ |
---|
150 | 153 | |
---|
151 | 154 | /* Parameters for PLL programming */ |
---|
152 | 155 | u32 fbd; /* PLL feedback divider */ |
---|
.. | .. |
---|
279 | 282 | |
---|
280 | 283 | static u32 tc358768_pll_to_pclk(struct tc358768_priv *priv, u32 pll_clk) |
---|
281 | 284 | { |
---|
282 | | - return (u32)div_u64((u64)pll_clk * priv->dsi_lanes, priv->pd_lines); |
---|
| 285 | + return (u32)div_u64((u64)pll_clk * priv->dsi_lanes, priv->dsi_bpp); |
---|
283 | 286 | } |
---|
284 | 287 | |
---|
285 | 288 | static u32 tc358768_pclk_to_pll(struct tc358768_priv *priv, u32 pclk) |
---|
286 | 289 | { |
---|
287 | | - return (u32)div_u64((u64)pclk * priv->pd_lines, priv->dsi_lanes); |
---|
| 290 | + return (u32)div_u64((u64)pclk * priv->dsi_bpp, priv->dsi_lanes); |
---|
288 | 291 | } |
---|
289 | 292 | |
---|
290 | 293 | static int tc358768_calc_pll(struct tc358768_priv *priv, |
---|
.. | .. |
---|
329 | 332 | u32 fbd; |
---|
330 | 333 | |
---|
331 | 334 | for (fbd = 0; fbd < 512; ++fbd) { |
---|
332 | | - u32 pll, diff; |
---|
| 335 | + u32 pll, diff, pll_in; |
---|
333 | 336 | |
---|
334 | 337 | pll = (u32)div_u64((u64)refclk * (fbd + 1), divisor); |
---|
335 | 338 | |
---|
336 | 339 | if (pll >= max_pll || pll < min_pll) |
---|
| 340 | + continue; |
---|
| 341 | + |
---|
| 342 | + pll_in = (u32)div_u64((u64)refclk, prd + 1); |
---|
| 343 | + if (pll_in < 4000000) |
---|
337 | 344 | continue; |
---|
338 | 345 | |
---|
339 | 346 | diff = max(pll, target_pll) - min(pll, target_pll); |
---|
.. | .. |
---|
417 | 424 | priv->output.panel = panel; |
---|
418 | 425 | |
---|
419 | 426 | priv->dsi_lanes = dev->lanes; |
---|
| 427 | + priv->dsi_bpp = mipi_dsi_pixel_format_to_bpp(dev->format); |
---|
420 | 428 | |
---|
421 | 429 | /* get input ep (port0/endpoint0) */ |
---|
422 | 430 | ret = -EINVAL; |
---|
.. | .. |
---|
428 | 436 | } |
---|
429 | 437 | |
---|
430 | 438 | if (ret) |
---|
431 | | - priv->pd_lines = mipi_dsi_pixel_format_to_bpp(dev->format); |
---|
| 439 | + priv->pd_lines = priv->dsi_bpp; |
---|
432 | 440 | |
---|
433 | 441 | drm_bridge_add(&priv->bridge); |
---|
434 | 442 | |
---|
.. | .. |
---|
626 | 634 | struct tc358768_priv *priv = bridge_to_tc358768(bridge); |
---|
627 | 635 | struct mipi_dsi_device *dsi_dev = priv->output.dev; |
---|
628 | 636 | u32 val, val2, lptxcnt, hact, data_type; |
---|
| 637 | + s32 raw_val; |
---|
629 | 638 | const struct drm_display_mode *mode; |
---|
630 | 639 | u32 dsibclk_nsk, dsiclk_nsk, ui_nsk, phy_delay_nsk; |
---|
631 | 640 | u32 dsiclk, dsibclk; |
---|
.. | .. |
---|
719 | 728 | |
---|
720 | 729 | /* 38ns < TCLK_PREPARE < 95ns */ |
---|
721 | 730 | val = tc358768_ns_to_cnt(65, dsibclk_nsk) - 1; |
---|
722 | | - /* TCLK_PREPARE > 300ns */ |
---|
723 | | - val2 = tc358768_ns_to_cnt(300 + tc358768_to_ns(3 * ui_nsk), |
---|
724 | | - dsibclk_nsk); |
---|
725 | | - val |= (val2 - tc358768_to_ns(phy_delay_nsk - dsibclk_nsk)) << 8; |
---|
| 731 | + /* TCLK_PREPARE + TCLK_ZERO > 300ns */ |
---|
| 732 | + val2 = tc358768_ns_to_cnt(300 - tc358768_to_ns(2 * ui_nsk), |
---|
| 733 | + dsibclk_nsk) - 2; |
---|
| 734 | + val |= val2 << 8; |
---|
726 | 735 | dev_dbg(priv->dev, "TCLK_HEADERCNT: 0x%x\n", val); |
---|
727 | 736 | tc358768_write(priv, TC358768_TCLK_HEADERCNT, val); |
---|
728 | 737 | |
---|
729 | | - /* TCLK_TRAIL > 60ns + 3*UI */ |
---|
730 | | - val = 60 + tc358768_to_ns(3 * ui_nsk); |
---|
731 | | - val = tc358768_ns_to_cnt(val, dsibclk_nsk) - 5; |
---|
| 738 | + /* TCLK_TRAIL > 60ns AND TEOT <= 105 ns + 12*UI */ |
---|
| 739 | + raw_val = tc358768_ns_to_cnt(60 + tc358768_to_ns(2 * ui_nsk), dsibclk_nsk) - 5; |
---|
| 740 | + val = clamp(raw_val, 0, 127); |
---|
732 | 741 | dev_dbg(priv->dev, "TCLK_TRAILCNT: 0x%x\n", val); |
---|
733 | 742 | tc358768_write(priv, TC358768_TCLK_TRAILCNT, val); |
---|
734 | 743 | |
---|
735 | 744 | /* 40ns + 4*UI < THS_PREPARE < 85ns + 6*UI */ |
---|
736 | 745 | val = 50 + tc358768_to_ns(4 * ui_nsk); |
---|
737 | 746 | val = tc358768_ns_to_cnt(val, dsibclk_nsk) - 1; |
---|
738 | | - /* THS_ZERO > 145ns + 10*UI */ |
---|
739 | | - val2 = tc358768_ns_to_cnt(145 - tc358768_to_ns(ui_nsk), dsibclk_nsk); |
---|
740 | | - val |= (val2 - tc358768_to_ns(phy_delay_nsk)) << 8; |
---|
| 747 | + /* THS_PREPARE + THS_ZERO > 145ns + 10*UI */ |
---|
| 748 | + raw_val = tc358768_ns_to_cnt(145 - tc358768_to_ns(3 * ui_nsk), dsibclk_nsk) - 10; |
---|
| 749 | + val2 = clamp(raw_val, 0, 127); |
---|
| 750 | + val |= val2 << 8; |
---|
741 | 751 | dev_dbg(priv->dev, "THS_HEADERCNT: 0x%x\n", val); |
---|
742 | 752 | tc358768_write(priv, TC358768_THS_HEADERCNT, val); |
---|
743 | 753 | |
---|
.. | .. |
---|
753 | 763 | dev_dbg(priv->dev, "TCLK_POSTCNT: 0x%x\n", val); |
---|
754 | 764 | tc358768_write(priv, TC358768_TCLK_POSTCNT, val); |
---|
755 | 765 | |
---|
756 | | - /* 60ns + 4*UI < THS_PREPARE < 105ns + 12*UI */ |
---|
757 | | - val = tc358768_ns_to_cnt(60 + tc358768_to_ns(15 * ui_nsk), |
---|
758 | | - dsibclk_nsk) - 5; |
---|
| 766 | + /* max(60ns + 4*UI, 8*UI) < THS_TRAILCNT < 105ns + 12*UI */ |
---|
| 767 | + raw_val = tc358768_ns_to_cnt(60 + tc358768_to_ns(18 * ui_nsk), |
---|
| 768 | + dsibclk_nsk) - 4; |
---|
| 769 | + val = clamp(raw_val, 0, 15); |
---|
759 | 770 | dev_dbg(priv->dev, "THS_TRAILCNT: 0x%x\n", val); |
---|
760 | 771 | tc358768_write(priv, TC358768_THS_TRAILCNT, val); |
---|
761 | 772 | |
---|
.. | .. |
---|
769 | 780 | |
---|
770 | 781 | /* TXTAGOCNT[26:16] RXTASURECNT[10:0] */ |
---|
771 | 782 | val = tc358768_to_ns((lptxcnt + 1) * dsibclk_nsk * 4); |
---|
772 | | - val = tc358768_ns_to_cnt(val, dsibclk_nsk) - 1; |
---|
| 783 | + val = tc358768_ns_to_cnt(val, dsibclk_nsk) / 4 - 1; |
---|
773 | 784 | val2 = tc358768_ns_to_cnt(tc358768_to_ns((lptxcnt + 1) * dsibclk_nsk), |
---|
774 | 785 | dsibclk_nsk) - 2; |
---|
775 | 786 | val |= val2 << 16; |
---|
.. | .. |
---|
819 | 830 | val = TC358768_DSI_CONFW_MODE_SET | TC358768_DSI_CONFW_ADDR_DSI_CONTROL; |
---|
820 | 831 | val |= (dsi_dev->lanes - 1) << 1; |
---|
821 | 832 | |
---|
822 | | - if (!(dsi_dev->mode_flags & MIPI_DSI_MODE_LPM)) |
---|
823 | | - val |= TC358768_DSI_CONTROL_TXMD; |
---|
| 833 | + val |= TC358768_DSI_CONTROL_TXMD; |
---|
824 | 834 | |
---|
825 | 835 | if (!(dsi_dev->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)) |
---|
826 | 836 | val |= TC358768_DSI_CONTROL_HSCKMD; |
---|
.. | .. |
---|
866 | 876 | } |
---|
867 | 877 | } |
---|
868 | 878 | |
---|
| 879 | +#define MAX_INPUT_SEL_FORMATS 1 |
---|
| 880 | + |
---|
| 881 | +static u32 * |
---|
| 882 | +tc358768_atomic_get_input_bus_fmts(struct drm_bridge *bridge, |
---|
| 883 | + struct drm_bridge_state *bridge_state, |
---|
| 884 | + struct drm_crtc_state *crtc_state, |
---|
| 885 | + struct drm_connector_state *conn_state, |
---|
| 886 | + u32 output_fmt, |
---|
| 887 | + unsigned int *num_input_fmts) |
---|
| 888 | +{ |
---|
| 889 | + struct tc358768_priv *priv = bridge_to_tc358768(bridge); |
---|
| 890 | + u32 *input_fmts; |
---|
| 891 | + |
---|
| 892 | + *num_input_fmts = 0; |
---|
| 893 | + |
---|
| 894 | + input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts), |
---|
| 895 | + GFP_KERNEL); |
---|
| 896 | + if (!input_fmts) |
---|
| 897 | + return NULL; |
---|
| 898 | + |
---|
| 899 | + switch (priv->pd_lines) { |
---|
| 900 | + case 16: |
---|
| 901 | + input_fmts[0] = MEDIA_BUS_FMT_RGB565_1X16; |
---|
| 902 | + break; |
---|
| 903 | + case 18: |
---|
| 904 | + input_fmts[0] = MEDIA_BUS_FMT_RGB666_1X18; |
---|
| 905 | + break; |
---|
| 906 | + default: |
---|
| 907 | + case 24: |
---|
| 908 | + input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24; |
---|
| 909 | + break; |
---|
| 910 | + }; |
---|
| 911 | + |
---|
| 912 | + *num_input_fmts = MAX_INPUT_SEL_FORMATS; |
---|
| 913 | + |
---|
| 914 | + return input_fmts; |
---|
| 915 | +} |
---|
| 916 | + |
---|
869 | 917 | static const struct drm_bridge_funcs tc358768_bridge_funcs = { |
---|
870 | 918 | .attach = tc358768_bridge_attach, |
---|
871 | 919 | .mode_valid = tc358768_bridge_mode_valid, |
---|
.. | .. |
---|
873 | 921 | .enable = tc358768_bridge_enable, |
---|
874 | 922 | .disable = tc358768_bridge_disable, |
---|
875 | 923 | .post_disable = tc358768_bridge_post_disable, |
---|
| 924 | + |
---|
| 925 | + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, |
---|
| 926 | + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, |
---|
| 927 | + .atomic_reset = drm_atomic_helper_bridge_reset, |
---|
| 928 | + .atomic_get_input_bus_fmts = tc358768_atomic_get_input_bus_fmts, |
---|
876 | 929 | }; |
---|
877 | 930 | |
---|
878 | 931 | static const struct drm_bridge_timings default_tc358768_timings = { |
---|