1*e2c0a7ffSGuochun Huang // SPDX-License-Identifier: GPL-2.0+ 2*e2c0a7ffSGuochun Huang /* 3*e2c0a7ffSGuochun Huang * (C) Copyright 2022 Rockchip Electronics Co., Ltd 4*e2c0a7ffSGuochun Huang */ 5*e2c0a7ffSGuochun Huang 6*e2c0a7ffSGuochun Huang #include <common.h> 7*e2c0a7ffSGuochun Huang #include <dm.h> 8*e2c0a7ffSGuochun Huang #include <errno.h> 9*e2c0a7ffSGuochun Huang #include <i2c.h> 10*e2c0a7ffSGuochun Huang #include <max96755f.h> 11*e2c0a7ffSGuochun Huang #include <video_bridge.h> 12*e2c0a7ffSGuochun Huang #include <dm/of_access.h> 13*e2c0a7ffSGuochun Huang #include <linux/media-bus-format.h> 14*e2c0a7ffSGuochun Huang 15*e2c0a7ffSGuochun Huang #include "rockchip_bridge.h" 16*e2c0a7ffSGuochun Huang #include "rockchip_display.h" 17*e2c0a7ffSGuochun Huang #include "rockchip_panel.h" 18*e2c0a7ffSGuochun Huang 19*e2c0a7ffSGuochun Huang static void max96755f_mipi_dsi_rx_config(struct max96755f_priv *priv) 20*e2c0a7ffSGuochun Huang { 21*e2c0a7ffSGuochun Huang struct drm_display_mode *mode = &priv->mode; 22*e2c0a7ffSGuochun Huang u32 hfp, hsa, hbp, hact; 23*e2c0a7ffSGuochun Huang u32 vact, vsa, vfp, vbp; 24*e2c0a7ffSGuochun Huang 25*e2c0a7ffSGuochun Huang dm_i2c_reg_clrset(priv->dev, 0x0331, NUM_LANES, 26*e2c0a7ffSGuochun Huang FIELD_PREP(NUM_LANES, priv->num_lanes - 1)); 27*e2c0a7ffSGuochun Huang if (!priv->dpi_deskew_en) 28*e2c0a7ffSGuochun Huang return; 29*e2c0a7ffSGuochun Huang 30*e2c0a7ffSGuochun Huang vact = mode->vdisplay; 31*e2c0a7ffSGuochun Huang vsa = mode->vsync_end - mode->vsync_start; 32*e2c0a7ffSGuochun Huang vfp = mode->vsync_start - mode->vdisplay; 33*e2c0a7ffSGuochun Huang vbp = mode->vtotal - mode->vsync_end; 34*e2c0a7ffSGuochun Huang hact = mode->hdisplay; 35*e2c0a7ffSGuochun Huang hsa = mode->hsync_end - mode->hsync_start; 36*e2c0a7ffSGuochun Huang hfp = mode->hsync_start - mode->hdisplay; 37*e2c0a7ffSGuochun Huang hbp = mode->htotal - mode->hsync_end; 38*e2c0a7ffSGuochun Huang dm_i2c_reg_write(priv->dev, 0x03A4, 0xc1); 39*e2c0a7ffSGuochun Huang dm_i2c_reg_write(priv->dev, 0x0385, FIELD_PREP(DPI_HSYNC_WIDTH_L, hsa)); 40*e2c0a7ffSGuochun Huang dm_i2c_reg_write(priv->dev, 0x0386, FIELD_PREP(DPI_VYSNC_WIDTH_L, vsa)); 41*e2c0a7ffSGuochun Huang dm_i2c_reg_write(priv->dev, 0x0387, 42*e2c0a7ffSGuochun Huang FIELD_PREP(DPI_VSYNC_WIDTH_H, (vsa >> 8)) | 43*e2c0a7ffSGuochun Huang FIELD_PREP(DPI_HSYNC_WIDTH_H, (hsa >> 8))); 44*e2c0a7ffSGuochun Huang dm_i2c_reg_write(priv->dev, 0x03a5, FIELD_PREP(DPI_VFP_L, vfp)); 45*e2c0a7ffSGuochun Huang dm_i2c_reg_write(priv->dev, 0x03a6, 46*e2c0a7ffSGuochun Huang FIELD_PREP(DPI_VBP_L, vbp) | 47*e2c0a7ffSGuochun Huang FIELD_PREP(DPI_VFP_H, (vfp >> 8))); 48*e2c0a7ffSGuochun Huang dm_i2c_reg_write(priv->dev, 0x03a7, FIELD_PREP(DPI_VBP_H, (vbp >> 4))); 49*e2c0a7ffSGuochun Huang dm_i2c_reg_write(priv->dev, 0x03a8, FIELD_PREP(DPI_VACT_L, vact)); 50*e2c0a7ffSGuochun Huang dm_i2c_reg_write(priv->dev, 0x03a9, FIELD_PREP(DPI_VACT_H, (vact >> 8))); 51*e2c0a7ffSGuochun Huang dm_i2c_reg_write(priv->dev, 0x03aa, FIELD_PREP(DPI_HFP_L, hfp)); 52*e2c0a7ffSGuochun Huang dm_i2c_reg_write(priv->dev, 0x03ab, 53*e2c0a7ffSGuochun Huang FIELD_PREP(DPI_HBP_L, hbp) | 54*e2c0a7ffSGuochun Huang FIELD_PREP(DPI_HFP_H, (hfp >> 7))); 55*e2c0a7ffSGuochun Huang dm_i2c_reg_write(priv->dev, 0x03ac, FIELD_PREP(DPI_HBP_H, (hbp >> 4))); 56*e2c0a7ffSGuochun Huang dm_i2c_reg_write(priv->dev, 0x03ad, FIELD_PREP(DPI_HACT_L, hact)); 57*e2c0a7ffSGuochun Huang dm_i2c_reg_write(priv->dev, 0x03ae, FIELD_PREP(DPI_HACT_H, (hact >> 8))); 58*e2c0a7ffSGuochun Huang } 59*e2c0a7ffSGuochun Huang 60*e2c0a7ffSGuochun Huang static void max96755f_bridge_enable(struct rockchip_bridge *bridge) 61*e2c0a7ffSGuochun Huang { 62*e2c0a7ffSGuochun Huang struct udevice *dev = bridge->dev; 63*e2c0a7ffSGuochun Huang struct max96755f_priv *priv = dev_get_priv(dev->parent); 64*e2c0a7ffSGuochun Huang 65*e2c0a7ffSGuochun Huang max96755f_mipi_dsi_rx_config(priv); 66*e2c0a7ffSGuochun Huang if (priv->split_mode) { 67*e2c0a7ffSGuochun Huang dm_i2c_reg_clrset(dev->parent, 0x0010, 68*e2c0a7ffSGuochun Huang RESET_ONESHOT | AUTO_LINK | LINK_CFG, 69*e2c0a7ffSGuochun Huang FIELD_PREP(RESET_ONESHOT, 1) | 70*e2c0a7ffSGuochun Huang FIELD_PREP(AUTO_LINK, 0) | 71*e2c0a7ffSGuochun Huang FIELD_PREP(LINK_CFG, SPLITTER_MODE)); 72*e2c0a7ffSGuochun Huang mdelay(50); 73*e2c0a7ffSGuochun Huang dm_i2c_reg_clrset(dev->parent, 0x0053, 74*e2c0a7ffSGuochun Huang TX_SPLIT_MASK_B | TX_SPLIT_MASK_A | TX_STR_SEL, 75*e2c0a7ffSGuochun Huang FIELD_PREP(TX_SPLIT_MASK_B, 0) | 76*e2c0a7ffSGuochun Huang FIELD_PREP(TX_SPLIT_MASK_A, 1) | 77*e2c0a7ffSGuochun Huang FIELD_PREP(TX_STR_SEL, 0)); 78*e2c0a7ffSGuochun Huang dm_i2c_reg_clrset(dev->parent, 0x0057, 79*e2c0a7ffSGuochun Huang TX_SPLIT_MASK_B | TX_SPLIT_MASK_A | TX_STR_SEL, 80*e2c0a7ffSGuochun Huang FIELD_PREP(TX_SPLIT_MASK_B, 1) | 81*e2c0a7ffSGuochun Huang FIELD_PREP(TX_SPLIT_MASK_A, 0) | 82*e2c0a7ffSGuochun Huang FIELD_PREP(TX_STR_SEL, 1)); 83*e2c0a7ffSGuochun Huang dm_i2c_reg_clrset(dev->parent, 0x032a, 84*e2c0a7ffSGuochun Huang DV_SWP_AB | DV_CONV | DV_SPL | DV_EN, 85*e2c0a7ffSGuochun Huang FIELD_PREP(DV_SWP_AB, priv->dv_swp_ab) | 86*e2c0a7ffSGuochun Huang FIELD_PREP(DV_CONV, 1) | 87*e2c0a7ffSGuochun Huang FIELD_PREP(DV_SPL, 1) | 88*e2c0a7ffSGuochun Huang FIELD_PREP(DV_EN, 1)); 89*e2c0a7ffSGuochun Huang dm_i2c_reg_clrset(dev->parent, 0x0311, 90*e2c0a7ffSGuochun Huang START_PORTAX | START_PORTAY, 91*e2c0a7ffSGuochun Huang FIELD_PREP(START_PORTAX, 1) | 92*e2c0a7ffSGuochun Huang FIELD_PREP(START_PORTAY, 1)); 93*e2c0a7ffSGuochun Huang dm_i2c_reg_clrset(dev->parent, 0x0002, 94*e2c0a7ffSGuochun Huang VID_TX_EN_X | VID_TX_EN_Y, 95*e2c0a7ffSGuochun Huang FIELD_PREP(VID_TX_EN_X, 1) | 96*e2c0a7ffSGuochun Huang FIELD_PREP(VID_TX_EN_Y, 1)); 97*e2c0a7ffSGuochun Huang 98*e2c0a7ffSGuochun Huang } else { 99*e2c0a7ffSGuochun Huang dm_i2c_reg_clrset(dev->parent, 0x0002, VID_TX_EN_X, 100*e2c0a7ffSGuochun Huang FIELD_PREP(VID_TX_EN_X, 1)); 101*e2c0a7ffSGuochun Huang dm_i2c_reg_clrset(dev->parent, 0x0311, START_PORTAX, 102*e2c0a7ffSGuochun Huang FIELD_PREP(START_PORTAX, 1)); 103*e2c0a7ffSGuochun Huang } 104*e2c0a7ffSGuochun Huang 105*e2c0a7ffSGuochun Huang dm_i2c_reg_clrset(dev->parent, 0x0010, RESET_ONESHOT, 106*e2c0a7ffSGuochun Huang FIELD_PREP(RESET_ONESHOT, 1)); 107*e2c0a7ffSGuochun Huang mdelay(100); 108*e2c0a7ffSGuochun Huang } 109*e2c0a7ffSGuochun Huang 110*e2c0a7ffSGuochun Huang static void max96755f_bridge_disable(struct rockchip_bridge *bridge) 111*e2c0a7ffSGuochun Huang { 112*e2c0a7ffSGuochun Huang struct udevice *dev = bridge->dev; 113*e2c0a7ffSGuochun Huang struct max96755f_priv *priv = dev_get_priv(dev->parent); 114*e2c0a7ffSGuochun Huang 115*e2c0a7ffSGuochun Huang dm_i2c_reg_clrset(dev->parent, 0x0002, VID_TX_EN_X, 116*e2c0a7ffSGuochun Huang FIELD_PREP(VID_TX_EN_X, 0)); 117*e2c0a7ffSGuochun Huang 118*e2c0a7ffSGuochun Huang if (priv->split_mode) 119*e2c0a7ffSGuochun Huang dm_i2c_reg_clrset(dev->parent, 0x0010, 120*e2c0a7ffSGuochun Huang AUTO_LINK | LINK_CFG, 121*e2c0a7ffSGuochun Huang FIELD_PREP(AUTO_LINK, 0) | 122*e2c0a7ffSGuochun Huang FIELD_PREP(LINK_CFG, LINKA)); 123*e2c0a7ffSGuochun Huang } 124*e2c0a7ffSGuochun Huang 125*e2c0a7ffSGuochun Huang static void max96755f_bridge_mode_set(struct rockchip_bridge *bridge, 126*e2c0a7ffSGuochun Huang const struct drm_display_mode *mode) 127*e2c0a7ffSGuochun Huang { 128*e2c0a7ffSGuochun Huang struct udevice *dev = bridge->dev; 129*e2c0a7ffSGuochun Huang struct max96755f_priv *priv = dev_get_priv(dev->parent); 130*e2c0a7ffSGuochun Huang 131*e2c0a7ffSGuochun Huang memcpy(&priv->mode, mode, sizeof(struct drm_display_mode)); 132*e2c0a7ffSGuochun Huang } 133*e2c0a7ffSGuochun Huang 134*e2c0a7ffSGuochun Huang static const struct rockchip_bridge_funcs max96755f_bridge_funcs = { 135*e2c0a7ffSGuochun Huang .enable = max96755f_bridge_enable, 136*e2c0a7ffSGuochun Huang .disable = max96755f_bridge_disable, 137*e2c0a7ffSGuochun Huang .mode_set = max96755f_bridge_mode_set, 138*e2c0a7ffSGuochun Huang }; 139*e2c0a7ffSGuochun Huang 140*e2c0a7ffSGuochun Huang static int max96755f_bridge_probe(struct udevice *dev) 141*e2c0a7ffSGuochun Huang { 142*e2c0a7ffSGuochun Huang struct rockchip_bridge *bridge; 143*e2c0a7ffSGuochun Huang struct max96755f_priv *priv = dev_get_priv(dev->parent); 144*e2c0a7ffSGuochun Huang 145*e2c0a7ffSGuochun Huang bridge = calloc(1, sizeof(*bridge)); 146*e2c0a7ffSGuochun Huang if (!bridge) 147*e2c0a7ffSGuochun Huang return -ENOMEM; 148*e2c0a7ffSGuochun Huang 149*e2c0a7ffSGuochun Huang dev->driver_data = (ulong)bridge; 150*e2c0a7ffSGuochun Huang bridge->dev = dev; 151*e2c0a7ffSGuochun Huang bridge->funcs = &max96755f_bridge_funcs; 152*e2c0a7ffSGuochun Huang 153*e2c0a7ffSGuochun Huang priv->num_lanes = dev_read_u32_default(dev, "dsi,lanes", 4); 154*e2c0a7ffSGuochun Huang priv->dv_swp_ab = dev_read_bool(dev, "vd-swap-ab"); 155*e2c0a7ffSGuochun Huang priv->dpi_deskew_en = dev_read_bool(dev, "dpi-deskew-en"); 156*e2c0a7ffSGuochun Huang 157*e2c0a7ffSGuochun Huang return 0; 158*e2c0a7ffSGuochun Huang } 159*e2c0a7ffSGuochun Huang 160*e2c0a7ffSGuochun Huang static const struct udevice_id max96755f_bridge_of_match[] = { 161*e2c0a7ffSGuochun Huang { .compatible = "maxim,max96755f-bridge", }, 162*e2c0a7ffSGuochun Huang { } 163*e2c0a7ffSGuochun Huang }; 164*e2c0a7ffSGuochun Huang 165*e2c0a7ffSGuochun Huang U_BOOT_DRIVER(max96755f_bridge) = { 166*e2c0a7ffSGuochun Huang .name = "max96755f_bridge", 167*e2c0a7ffSGuochun Huang .id = UCLASS_VIDEO_BRIDGE, 168*e2c0a7ffSGuochun Huang .of_match = max96755f_bridge_of_match, 169*e2c0a7ffSGuochun Huang .probe = max96755f_bridge_probe, 170*e2c0a7ffSGuochun Huang }; 171