1186f8572SMark Yao /* 2186f8572SMark Yao * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd 3186f8572SMark Yao * 4186f8572SMark Yao * SPDX-License-Identifier: GPL-2.0+ 5186f8572SMark Yao */ 6186f8572SMark Yao 7186f8572SMark Yao #include <config.h> 8186f8572SMark Yao #include <common.h> 9186f8572SMark Yao #include <errno.h> 10186f8572SMark Yao #include <dm/device.h> 119aa59efbSKever Yang #include <dm/read.h> 129aa59efbSKever Yang #include <dm/ofnode.h> 13cb17ca6cSSandy Huang #include <dm/of_access.h> 14186f8572SMark Yao #include <syscon.h> 15b69d3ed4SWyon Bi #include <regmap.h> 16b69d3ed4SWyon Bi #include <dm/device.h> 17b69d3ed4SWyon Bi #include <dm/read.h> 18b69d3ed4SWyon Bi #include <linux/media-bus-format.h> 19186f8572SMark Yao 20186f8572SMark Yao #include "rockchip_display.h" 21186f8572SMark Yao #include "rockchip_connector.h" 22b69d3ed4SWyon Bi #include "rockchip_phy.h" 231a8d717cSWyon Bi #include "rockchip_panel.h" 24*dcebcd68SChaoyi Chen #include "drm_of.h" 251953e619SWyon Bi 261953e619SWyon Bi #define HIWORD_UPDATE(v, h, l) (((v) << (l)) | (GENMASK(h, l) << 16)) 27186f8572SMark Yao 28b69d3ed4SWyon Bi #define PX30_GRF_PD_VO_CON1 0x0438 29b69d3ed4SWyon Bi #define PX30_LVDS_SELECT(x) HIWORD_UPDATE(x, 14, 13) 30b69d3ed4SWyon Bi #define PX30_LVDS_MODE_EN(x) HIWORD_UPDATE(x, 12, 12) 31b69d3ed4SWyon Bi #define PX30_LVDS_MSBSEL(x) HIWORD_UPDATE(x, 11, 11) 3231018a86SWyon Bi #define PX30_LVDS_P2S_EN(x) HIWORD_UPDATE(x, 6, 6) 33b69d3ed4SWyon Bi #define PX30_LVDS_VOP_SEL(x) HIWORD_UPDATE(x, 1, 1) 34b69d3ed4SWyon Bi 35b69d3ed4SWyon Bi #define RK3126_GRF_LVDS_CON0 0x0150 36b69d3ed4SWyon Bi #define RK3126_LVDS_P2S_EN(x) HIWORD_UPDATE(x, 9, 9) 37b69d3ed4SWyon Bi #define RK3126_LVDS_MODE_EN(x) HIWORD_UPDATE(x, 6, 6) 38b69d3ed4SWyon Bi #define RK3126_LVDS_MSBSEL(x) HIWORD_UPDATE(x, 3, 3) 39b69d3ed4SWyon Bi #define RK3126_LVDS_SELECT(x) HIWORD_UPDATE(x, 2, 1) 40b69d3ed4SWyon Bi 41b69d3ed4SWyon Bi #define RK3288_GRF_SOC_CON6 0x025c 42b69d3ed4SWyon Bi #define RK3288_LVDS_LCDC_SEL(x) HIWORD_UPDATE(x, 3, 3) 43b69d3ed4SWyon Bi #define RK3288_GRF_SOC_CON7 0x0260 44b69d3ed4SWyon Bi #define RK3288_LVDS_PWRDWN(x) HIWORD_UPDATE(x, 15, 15) 45b69d3ed4SWyon Bi #define RK3288_LVDS_CON_ENABLE_2(x) HIWORD_UPDATE(x, 12, 12) 46b69d3ed4SWyon Bi #define RK3288_LVDS_CON_ENABLE_1(x) HIWORD_UPDATE(x, 11, 11) 47b69d3ed4SWyon Bi #define RK3288_LVDS_CON_DEN_POL(x) HIWORD_UPDATE(x, 10, 10) 48b69d3ed4SWyon Bi #define RK3288_LVDS_CON_HS_POL(x) HIWORD_UPDATE(x, 9, 9) 49b69d3ed4SWyon Bi #define RK3288_LVDS_CON_CLKINV(x) HIWORD_UPDATE(x, 8, 8) 50b69d3ed4SWyon Bi #define RK3288_LVDS_CON_STARTPHASE(x) HIWORD_UPDATE(x, 7, 7) 51b69d3ed4SWyon Bi #define RK3288_LVDS_CON_TTL_EN(x) HIWORD_UPDATE(x, 6, 6) 52b69d3ed4SWyon Bi #define RK3288_LVDS_CON_STARTSEL(x) HIWORD_UPDATE(x, 5, 5) 53b69d3ed4SWyon Bi #define RK3288_LVDS_CON_CHASEL(x) HIWORD_UPDATE(x, 4, 4) 54b69d3ed4SWyon Bi #define RK3288_LVDS_CON_MSBSEL(x) HIWORD_UPDATE(x, 3, 3) 55b69d3ed4SWyon Bi #define RK3288_LVDS_CON_SELECT(x) HIWORD_UPDATE(x, 2, 0) 56b69d3ed4SWyon Bi 57b69d3ed4SWyon Bi #define RK3368_GRF_SOC_CON7 0x041c 58b69d3ed4SWyon Bi #define RK3368_LVDS_SELECT(x) HIWORD_UPDATE(x, 14, 13) 59b69d3ed4SWyon Bi #define RK3368_LVDS_MODE_EN(x) HIWORD_UPDATE(x, 12, 12) 60b69d3ed4SWyon Bi #define RK3368_LVDS_MSBSEL(x) HIWORD_UPDATE(x, 11, 11) 61b69d3ed4SWyon Bi #define RK3368_LVDS_P2S_EN(x) HIWORD_UPDATE(x, 6, 6) 62b69d3ed4SWyon Bi 63cc341c3bSZhang Yubing #define RK3562_GRF_VO_CON0 0x05d0 64cc341c3bSZhang Yubing #define RK3562_GRF_VO_CON1 0x05d4 65cc341c3bSZhang Yubing 66aeb5dd22SSandy Huang #define RK3568_GRF_VO_CON0 0x0360 67aeb5dd22SSandy Huang #define RK3568_LVDS1_SELECT(x) HIWORD_UPDATE(x, 13, 12) 68aeb5dd22SSandy Huang #define RK3568_LVDS1_MSBSEL(x) HIWORD_UPDATE(x, 11, 11) 69aeb5dd22SSandy Huang #define RK3568_LVDS0_SELECT(x) HIWORD_UPDATE(x, 5, 4) 70aeb5dd22SSandy Huang #define RK3568_LVDS0_MSBSEL(x) HIWORD_UPDATE(x, 3, 3) 71aeb5dd22SSandy Huang #define RK3568_GRF_VO_CON2 0x0368 72aeb5dd22SSandy Huang #define RK3568_LVDS0_DCLK_INV_SEL(x) HIWORD_UPDATE(x, 9, 9) 73aeb5dd22SSandy Huang #define RK3568_LVDS0_DCLK_DIV2_SEL(x) HIWORD_UPDATE(x, 8, 8) 74aeb5dd22SSandy Huang #define RK3568_LVDS0_MODE_EN(x) HIWORD_UPDATE(x, 1, 1) 75aeb5dd22SSandy Huang #define RK3568_LVDS0_P2S_EN(x) HIWORD_UPDATE(x, 0, 0) 76aeb5dd22SSandy Huang #define RK3568_GRF_VO_CON3 0x036c 77aeb5dd22SSandy Huang #define RK3568_LVDS1_DCLK_INV_SEL(x) HIWORD_UPDATE(x, 9, 9) 78aeb5dd22SSandy Huang #define RK3568_LVDS1_DCLK_DIV2_SEL(x) HIWORD_UPDATE(x, 8, 8) 79aeb5dd22SSandy Huang #define RK3568_LVDS1_MODE_EN(x) HIWORD_UPDATE(x, 1, 1) 80aeb5dd22SSandy Huang #define RK3568_LVDS1_P2S_EN(x) HIWORD_UPDATE(x, 0, 0) 81aeb5dd22SSandy Huang 82b69d3ed4SWyon Bi enum lvds_format { 83b69d3ed4SWyon Bi LVDS_8BIT_MODE_FORMAT_1, 84b69d3ed4SWyon Bi LVDS_8BIT_MODE_FORMAT_2, 85b69d3ed4SWyon Bi LVDS_8BIT_MODE_FORMAT_3, 86b69d3ed4SWyon Bi LVDS_6BIT_MODE, 87e2721f29SGuochun Huang LVDS_10BIT_MODE_FORMAT_1, 88e2721f29SGuochun Huang LVDS_10BIT_MODE_FORMAT_2, 89186f8572SMark Yao }; 90186f8572SMark Yao 91b69d3ed4SWyon Bi struct rockchip_lvds; 92b69d3ed4SWyon Bi 93b69d3ed4SWyon Bi struct rockchip_lvds_funcs { 94*dcebcd68SChaoyi Chen int (*probe)(struct rockchip_lvds *lvds); 95b69d3ed4SWyon Bi void (*enable)(struct rockchip_lvds *lvds, int pipe); 96b69d3ed4SWyon Bi void (*disable)(struct rockchip_lvds *lvds); 97186f8572SMark Yao }; 98186f8572SMark Yao 99b69d3ed4SWyon Bi struct rockchip_lvds { 1000594ce39SZhang Yubing struct rockchip_connector connector; 101cb17ca6cSSandy Huang int id; 102b69d3ed4SWyon Bi struct udevice *dev; 103b69d3ed4SWyon Bi struct regmap *grf; 104b69d3ed4SWyon Bi struct rockchip_phy *phy; 105b69d3ed4SWyon Bi const struct drm_display_mode *mode; 106b69d3ed4SWyon Bi const struct rockchip_lvds_funcs *funcs; 107b69d3ed4SWyon Bi enum lvds_format format; 108b69d3ed4SWyon Bi bool data_swap; 109b69d3ed4SWyon Bi bool dual_channel; 110*dcebcd68SChaoyi Chen enum drm_lvds_dual_link_pixels pixel_order; 111186f8572SMark Yao }; 112186f8572SMark Yao 1130594ce39SZhang Yubing static int rockchip_lvds_connector_init(struct rockchip_connector *conn, 1140594ce39SZhang Yubing struct display_state *state) 115186f8572SMark Yao { 1160594ce39SZhang Yubing struct rockchip_lvds *lvds = dev_get_priv(conn->dev); 117*dcebcd68SChaoyi Chen struct rockchip_lvds *primary_lvds = NULL; 118186f8572SMark Yao struct connector_state *conn_state = &state->conn_state; 1190594ce39SZhang Yubing struct rockchip_panel *panel = conn->panel; 120186f8572SMark Yao 121b69d3ed4SWyon Bi lvds->mode = &conn_state->mode; 1220594ce39SZhang Yubing lvds->phy = conn->phy; 123cb17ca6cSSandy Huang conn_state->disp_info = rockchip_get_disp_info(conn_state->type, lvds->id); 124186f8572SMark Yao 125*dcebcd68SChaoyi Chen if (conn_state->secondary) 126*dcebcd68SChaoyi Chen primary_lvds = dev_get_priv(conn_state->connector->dev); 127*dcebcd68SChaoyi Chen 128b69d3ed4SWyon Bi switch (panel->bus_format) { 1294888f8a4SWyon Bi case MEDIA_BUS_FMT_RGB666_1X7X3_JEIDA: /* jeida-18 */ 130b69d3ed4SWyon Bi lvds->format = LVDS_6BIT_MODE; 131b69d3ed4SWyon Bi break; 132b69d3ed4SWyon Bi case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: /* jeida-24 */ 133b69d3ed4SWyon Bi lvds->format = LVDS_8BIT_MODE_FORMAT_2; 134b69d3ed4SWyon Bi break; 135e2721f29SGuochun Huang case MEDIA_BUS_FMT_RGB101010_1X7X5_JEIDA: /* jeida-30 */ 136e2721f29SGuochun Huang lvds->format = LVDS_10BIT_MODE_FORMAT_1; 1374888f8a4SWyon Bi case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: /* vesa-18 */ 1384888f8a4SWyon Bi lvds->format = LVDS_8BIT_MODE_FORMAT_3; 1394888f8a4SWyon Bi break; 140e2721f29SGuochun Huang case MEDIA_BUS_FMT_RGB101010_1X7X5_SPWG: /* vesa-30 */ 141e2721f29SGuochun Huang lvds->format = LVDS_10BIT_MODE_FORMAT_2; 142e2721f29SGuochun Huang break; 143b69d3ed4SWyon Bi case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: /* vesa-24 */ 144b69d3ed4SWyon Bi default: 145b69d3ed4SWyon Bi lvds->format = LVDS_8BIT_MODE_FORMAT_1; 146b69d3ed4SWyon Bi break; 147186f8572SMark Yao } 148186f8572SMark Yao 149*dcebcd68SChaoyi Chen conn_state->bus_format = panel->bus_format; 150186f8572SMark Yao conn_state->output_mode = ROCKCHIP_OUT_MODE_P888; 151e2721f29SGuochun Huang 152e2721f29SGuochun Huang if ((lvds->format == LVDS_10BIT_MODE_FORMAT_1) || 153e2721f29SGuochun Huang (lvds->format == LVDS_10BIT_MODE_FORMAT_2)) 154e2721f29SGuochun Huang conn_state->output_mode = ROCKCHIP_OUT_MODE_AAAA; 155e2721f29SGuochun Huang 15679feefb1SSandy Huang conn_state->color_space = V4L2_COLORSPACE_DEFAULT; 157*dcebcd68SChaoyi Chen if (primary_lvds) { 158*dcebcd68SChaoyi Chen conn_state->output_flags = 0; 159*dcebcd68SChaoyi Chen conn_state->output_if = 0; 160*dcebcd68SChaoyi Chen 161*dcebcd68SChaoyi Chen switch (primary_lvds->pixel_order) { 162*dcebcd68SChaoyi Chen case DRM_LVDS_DUAL_LINK_ODD_EVEN_PIXELS: 163*dcebcd68SChaoyi Chen conn_state->output_flags |= 164*dcebcd68SChaoyi Chen ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE; 165*dcebcd68SChaoyi Chen conn_state->output_if |= 166*dcebcd68SChaoyi Chen VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0; 167*dcebcd68SChaoyi Chen break; 168*dcebcd68SChaoyi Chen case DRM_LVDS_DUAL_LINK_EVEN_ODD_PIXELS: 169*dcebcd68SChaoyi Chen conn_state->output_flags |= 170*dcebcd68SChaoyi Chen ROCKCHIP_OUTPUT_DUAL_CHANNEL_ODD_EVEN_MODE; 171*dcebcd68SChaoyi Chen conn_state->output_flags |= ROCKCHIP_OUTPUT_DATA_SWAP; 172*dcebcd68SChaoyi Chen conn_state->output_if |= 173*dcebcd68SChaoyi Chen VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0; 174*dcebcd68SChaoyi Chen break; 175*dcebcd68SChaoyi Chen case DRM_LVDS_DUAL_LINK_LEFT_RIGHT_PIXELS: 176*dcebcd68SChaoyi Chen conn_state->output_flags |= 177*dcebcd68SChaoyi Chen ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE; 178*dcebcd68SChaoyi Chen conn_state->output_if |= 179*dcebcd68SChaoyi Chen VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0; 180*dcebcd68SChaoyi Chen break; 181*dcebcd68SChaoyi Chen case DRM_LVDS_DUAL_LINK_RIGHT_LEFT_PIXELS: 182*dcebcd68SChaoyi Chen conn_state->output_flags |= 183*dcebcd68SChaoyi Chen ROCKCHIP_OUTPUT_DUAL_CHANNEL_LEFT_RIGHT_MODE; 184*dcebcd68SChaoyi Chen conn_state->output_flags |= ROCKCHIP_OUTPUT_DATA_SWAP; 185*dcebcd68SChaoyi Chen conn_state->output_if |= 186*dcebcd68SChaoyi Chen VOP_OUTPUT_IF_LVDS1 | VOP_OUTPUT_IF_LVDS0; 187*dcebcd68SChaoyi Chen break; 188*dcebcd68SChaoyi Chen default: 189*dcebcd68SChaoyi Chen break; 190*dcebcd68SChaoyi Chen } 191*dcebcd68SChaoyi Chen } 192*dcebcd68SChaoyi Chen 193*dcebcd68SChaoyi Chen if (lvds->id) 194*dcebcd68SChaoyi Chen conn_state->output_if |= VOP_OUTPUT_IF_LVDS1; 195*dcebcd68SChaoyi Chen else 196*dcebcd68SChaoyi Chen conn_state->output_if |= VOP_OUTPUT_IF_LVDS0; 197186f8572SMark Yao 198186f8572SMark Yao return 0; 199186f8572SMark Yao } 200186f8572SMark Yao 2010594ce39SZhang Yubing static int rockchip_lvds_connector_enable(struct rockchip_connector *conn, 2020594ce39SZhang Yubing struct display_state *state) 203186f8572SMark Yao { 2040594ce39SZhang Yubing struct rockchip_lvds *lvds = dev_get_priv(conn->dev); 205b69d3ed4SWyon Bi struct crtc_state *crtc_state = &state->crtc_state; 206b69d3ed4SWyon Bi int pipe = crtc_state->crtc_id; 207b69d3ed4SWyon Bi int ret; 208186f8572SMark Yao 209b69d3ed4SWyon Bi if (lvds->funcs->enable) 210b69d3ed4SWyon Bi lvds->funcs->enable(lvds, pipe); 211b69d3ed4SWyon Bi 2129e3ffb10SGuochun Huang ret = rockchip_phy_set_mode(lvds->phy, PHY_MODE_VIDEO_LVDS); 213b69d3ed4SWyon Bi if (ret) { 214b69d3ed4SWyon Bi dev_err(lvds->dev, "failed to set phy mode: %d\n", ret); 215b69d3ed4SWyon Bi return ret; 216186f8572SMark Yao } 217186f8572SMark Yao 218b69d3ed4SWyon Bi rockchip_phy_power_on(lvds->phy); 219186f8572SMark Yao 220186f8572SMark Yao return 0; 221186f8572SMark Yao } 222186f8572SMark Yao 2230594ce39SZhang Yubing static int rockchip_lvds_connector_disable(struct rockchip_connector *conn, 2240594ce39SZhang Yubing struct display_state *state) 225186f8572SMark Yao { 2260594ce39SZhang Yubing struct rockchip_lvds *lvds = dev_get_priv(conn->dev); 227b69d3ed4SWyon Bi 228b69d3ed4SWyon Bi rockchip_phy_power_off(lvds->phy); 229b69d3ed4SWyon Bi 230b69d3ed4SWyon Bi if (lvds->funcs->disable) 231b69d3ed4SWyon Bi lvds->funcs->disable(lvds); 232b69d3ed4SWyon Bi 233b69d3ed4SWyon Bi return 0; 234b69d3ed4SWyon Bi } 235b69d3ed4SWyon Bi 236b69d3ed4SWyon Bi static const struct rockchip_connector_funcs rockchip_lvds_connector_funcs = { 237b69d3ed4SWyon Bi .init = rockchip_lvds_connector_init, 238b69d3ed4SWyon Bi .enable = rockchip_lvds_connector_enable, 239b69d3ed4SWyon Bi .disable = rockchip_lvds_connector_disable, 240b69d3ed4SWyon Bi }; 241b69d3ed4SWyon Bi 242b69d3ed4SWyon Bi static int rockchip_lvds_probe(struct udevice *dev) 243b69d3ed4SWyon Bi { 244b69d3ed4SWyon Bi struct rockchip_lvds *lvds = dev_get_priv(dev); 245b69d3ed4SWyon Bi 246b69d3ed4SWyon Bi lvds->dev = dev; 2470594ce39SZhang Yubing lvds->funcs = (const struct rockchip_lvds_funcs *)dev_get_driver_data(dev); 248b69d3ed4SWyon Bi lvds->grf = syscon_get_regmap(dev_get_parent(dev)); 249b69d3ed4SWyon Bi lvds->dual_channel = dev_read_bool(dev, "dual-channel"); 250b69d3ed4SWyon Bi lvds->data_swap = dev_read_bool(dev, "rockchip,data-swap"); 251cb17ca6cSSandy Huang lvds->id = of_alias_get_id(ofnode_to_np(dev->node), "lvds"); 252cb17ca6cSSandy Huang if (lvds->id < 0) 253cb17ca6cSSandy Huang lvds->id = 0; 254b69d3ed4SWyon Bi 255*dcebcd68SChaoyi Chen lvds->pixel_order = -1; 256*dcebcd68SChaoyi Chen if (lvds->funcs->probe) 257*dcebcd68SChaoyi Chen lvds->funcs->probe(lvds); 258*dcebcd68SChaoyi Chen 2590594ce39SZhang Yubing rockchip_connector_bind(&lvds->connector, dev, lvds->id, &rockchip_lvds_connector_funcs, 2600594ce39SZhang Yubing NULL, DRM_MODE_CONNECTOR_LVDS); 2610594ce39SZhang Yubing 262b69d3ed4SWyon Bi return 0; 263b69d3ed4SWyon Bi } 264b69d3ed4SWyon Bi 265b69d3ed4SWyon Bi static void px30_lvds_enable(struct rockchip_lvds *lvds, int pipe) 266b69d3ed4SWyon Bi { 267b69d3ed4SWyon Bi regmap_write(lvds->grf, PX30_GRF_PD_VO_CON1, 268b69d3ed4SWyon Bi PX30_LVDS_SELECT(lvds->format) | 269b69d3ed4SWyon Bi PX30_LVDS_MODE_EN(1) | PX30_LVDS_MSBSEL(1) | 270b69d3ed4SWyon Bi PX30_LVDS_P2S_EN(1) | PX30_LVDS_VOP_SEL(pipe)); 271b69d3ed4SWyon Bi } 272b69d3ed4SWyon Bi 273b69d3ed4SWyon Bi static void px30_lvds_disable(struct rockchip_lvds *lvds) 274b69d3ed4SWyon Bi { 275b69d3ed4SWyon Bi regmap_write(lvds->grf, PX30_GRF_PD_VO_CON1, 276b69d3ed4SWyon Bi PX30_LVDS_MODE_EN(0) | PX30_LVDS_P2S_EN(0)); 277b69d3ed4SWyon Bi } 278b69d3ed4SWyon Bi 279b69d3ed4SWyon Bi static const struct rockchip_lvds_funcs px30_lvds_funcs = { 280b69d3ed4SWyon Bi .enable = px30_lvds_enable, 281b69d3ed4SWyon Bi .disable = px30_lvds_disable, 282b69d3ed4SWyon Bi }; 283b69d3ed4SWyon Bi 284b69d3ed4SWyon Bi static void rk3126_lvds_enable(struct rockchip_lvds *lvds, int pipe) 285b69d3ed4SWyon Bi { 286b69d3ed4SWyon Bi regmap_write(lvds->grf, RK3126_GRF_LVDS_CON0, 287b69d3ed4SWyon Bi RK3126_LVDS_P2S_EN(1) | RK3126_LVDS_MODE_EN(1) | 288b69d3ed4SWyon Bi RK3126_LVDS_MSBSEL(1) | RK3126_LVDS_SELECT(lvds->format)); 289b69d3ed4SWyon Bi } 290b69d3ed4SWyon Bi 291b69d3ed4SWyon Bi static void rk3126_lvds_disable(struct rockchip_lvds *lvds) 292b69d3ed4SWyon Bi { 293b69d3ed4SWyon Bi regmap_write(lvds->grf, RK3126_GRF_LVDS_CON0, 294b69d3ed4SWyon Bi RK3126_LVDS_P2S_EN(0) | RK3126_LVDS_MODE_EN(0)); 295b69d3ed4SWyon Bi } 296b69d3ed4SWyon Bi 297b69d3ed4SWyon Bi static const struct rockchip_lvds_funcs rk3126_lvds_funcs = { 298b69d3ed4SWyon Bi .enable = rk3126_lvds_enable, 299b69d3ed4SWyon Bi .disable = rk3126_lvds_disable, 300b69d3ed4SWyon Bi }; 301b69d3ed4SWyon Bi 302b69d3ed4SWyon Bi static void rk3288_lvds_enable(struct rockchip_lvds *lvds, int pipe) 303b69d3ed4SWyon Bi { 304b69d3ed4SWyon Bi const struct drm_display_mode *mode = lvds->mode; 305186f8572SMark Yao u32 val; 306186f8572SMark Yao 307b69d3ed4SWyon Bi regmap_write(lvds->grf, RK3288_GRF_SOC_CON6, 308b69d3ed4SWyon Bi RK3288_LVDS_LCDC_SEL(pipe)); 309b69d3ed4SWyon Bi 310b69d3ed4SWyon Bi val = RK3288_LVDS_PWRDWN(0) | RK3288_LVDS_CON_CLKINV(0) | 311b69d3ed4SWyon Bi RK3288_LVDS_CON_CHASEL(lvds->dual_channel) | 312b69d3ed4SWyon Bi RK3288_LVDS_CON_SELECT(lvds->format); 313b69d3ed4SWyon Bi 314b69d3ed4SWyon Bi if (lvds->dual_channel) { 315b69d3ed4SWyon Bi u32 h_bp = mode->htotal - mode->hsync_start; 316b69d3ed4SWyon Bi 317b69d3ed4SWyon Bi val |= RK3288_LVDS_CON_ENABLE_2(1) | 318b69d3ed4SWyon Bi RK3288_LVDS_CON_ENABLE_1(1) | 319b69d3ed4SWyon Bi RK3288_LVDS_CON_STARTSEL(lvds->data_swap); 320b69d3ed4SWyon Bi 321b69d3ed4SWyon Bi if (h_bp % 2) 322b69d3ed4SWyon Bi val |= RK3288_LVDS_CON_STARTPHASE(1); 323186f8572SMark Yao else 324b69d3ed4SWyon Bi val |= RK3288_LVDS_CON_STARTPHASE(0); 325186f8572SMark Yao } else { 326b69d3ed4SWyon Bi val |= RK3288_LVDS_CON_ENABLE_2(0) | 327b69d3ed4SWyon Bi RK3288_LVDS_CON_ENABLE_1(1); 328186f8572SMark Yao } 329186f8572SMark Yao 330b69d3ed4SWyon Bi regmap_write(lvds->grf, RK3288_GRF_SOC_CON7, val); 331b69d3ed4SWyon Bi 332b69d3ed4SWyon Bi rockchip_phy_set_bus_width(lvds->phy, lvds->dual_channel ? 2 : 1); 333186f8572SMark Yao } 334186f8572SMark Yao 335b69d3ed4SWyon Bi static void rk3288_lvds_disable(struct rockchip_lvds *lvds) 336186f8572SMark Yao { 337b69d3ed4SWyon Bi regmap_write(lvds->grf, RK3288_GRF_SOC_CON7, RK3288_LVDS_PWRDWN(1)); 338186f8572SMark Yao } 339186f8572SMark Yao 340b69d3ed4SWyon Bi static const struct rockchip_lvds_funcs rk3288_lvds_funcs = { 341b69d3ed4SWyon Bi .enable = rk3288_lvds_enable, 342b69d3ed4SWyon Bi .disable = rk3288_lvds_disable, 343186f8572SMark Yao }; 344186f8572SMark Yao 345b69d3ed4SWyon Bi static void rk3368_lvds_enable(struct rockchip_lvds *lvds, int pipe) 346b69d3ed4SWyon Bi { 347b69d3ed4SWyon Bi regmap_write(lvds->grf, RK3368_GRF_SOC_CON7, 348b69d3ed4SWyon Bi RK3368_LVDS_SELECT(lvds->format) | 349b69d3ed4SWyon Bi RK3368_LVDS_MODE_EN(1) | RK3368_LVDS_MSBSEL(1) | 350b69d3ed4SWyon Bi RK3368_LVDS_P2S_EN(1)); 351b69d3ed4SWyon Bi } 352b69d3ed4SWyon Bi 353b69d3ed4SWyon Bi static void rk3368_lvds_disable(struct rockchip_lvds *lvds) 354b69d3ed4SWyon Bi { 355b69d3ed4SWyon Bi regmap_write(lvds->grf, RK3368_GRF_SOC_CON7, 356b69d3ed4SWyon Bi RK3368_LVDS_MODE_EN(0) | RK3368_LVDS_P2S_EN(0)); 357b69d3ed4SWyon Bi } 358b69d3ed4SWyon Bi 359b69d3ed4SWyon Bi static const struct rockchip_lvds_funcs rk3368_lvds_funcs = { 360b69d3ed4SWyon Bi .enable = rk3368_lvds_enable, 361b69d3ed4SWyon Bi .disable = rk3368_lvds_disable, 36230d6d433SWyon Bi }; 36330d6d433SWyon Bi 364cc341c3bSZhang Yubing static void rk3562_lvds_enable(struct rockchip_lvds *lvds, int pipe) 365cc341c3bSZhang Yubing { 366cc341c3bSZhang Yubing regmap_write(lvds->grf, RK3562_GRF_VO_CON1, 367cc341c3bSZhang Yubing RK3568_LVDS0_MODE_EN(1) | RK3568_LVDS0_P2S_EN(1) | 368cc341c3bSZhang Yubing RK3568_LVDS0_DCLK_INV_SEL(1)); 369cc341c3bSZhang Yubing regmap_write(lvds->grf, RK3562_GRF_VO_CON0, 370cc341c3bSZhang Yubing RK3568_LVDS0_SELECT(lvds->format) | RK3568_LVDS0_MSBSEL(1)); 371cc341c3bSZhang Yubing } 372cc341c3bSZhang Yubing 373cc341c3bSZhang Yubing static void rk3562_lvds_disable(struct rockchip_lvds *lvds) 374cc341c3bSZhang Yubing { 375cc341c3bSZhang Yubing regmap_write(lvds->grf, RK3562_GRF_VO_CON1, RK3568_LVDS0_MODE_EN(0)); 376cc341c3bSZhang Yubing } 377cc341c3bSZhang Yubing 378cc341c3bSZhang Yubing static const struct rockchip_lvds_funcs rk3562_lvds_funcs = { 379cc341c3bSZhang Yubing .enable = rk3562_lvds_enable, 380cc341c3bSZhang Yubing .disable = rk3562_lvds_disable, 381cc341c3bSZhang Yubing }; 382cc341c3bSZhang Yubing 383*dcebcd68SChaoyi Chen static int rk3568_lvds_probe(struct rockchip_lvds *lvds) 384*dcebcd68SChaoyi Chen { 385*dcebcd68SChaoyi Chen if (lvds->dual_channel) { 386*dcebcd68SChaoyi Chen const struct device_node *port0, *port1; 387*dcebcd68SChaoyi Chen int pixel_order; 388*dcebcd68SChaoyi Chen 389*dcebcd68SChaoyi Chen port1 = of_alias_get_dev("lvds", 1); 390*dcebcd68SChaoyi Chen if (!port1 || !of_device_is_available(port1)) { 391*dcebcd68SChaoyi Chen lvds->pixel_order = 0; 392*dcebcd68SChaoyi Chen return 0; 393*dcebcd68SChaoyi Chen } 394*dcebcd68SChaoyi Chen 395*dcebcd68SChaoyi Chen port0 = rockchip_of_graph_get_port_by_id(lvds->dev->node, 1); 396*dcebcd68SChaoyi Chen port1 = rockchip_of_graph_get_port_by_id(np_to_ofnode(port1), 397*dcebcd68SChaoyi Chen 1); 398*dcebcd68SChaoyi Chen pixel_order = 399*dcebcd68SChaoyi Chen drm_of_lvds_get_dual_link_pixel_order(port0, port1); 400*dcebcd68SChaoyi Chen 401*dcebcd68SChaoyi Chen lvds->pixel_order = pixel_order >= 0 ? pixel_order : 0; 402*dcebcd68SChaoyi Chen } 403*dcebcd68SChaoyi Chen 404*dcebcd68SChaoyi Chen return 0; 405*dcebcd68SChaoyi Chen } 406*dcebcd68SChaoyi Chen 407aeb5dd22SSandy Huang static void rk3568_lvds_enable(struct rockchip_lvds *lvds, int pipe) 408aeb5dd22SSandy Huang { 409*dcebcd68SChaoyi Chen if (lvds->id) { 410*dcebcd68SChaoyi Chen regmap_write(lvds->grf, RK3568_GRF_VO_CON3, 411*dcebcd68SChaoyi Chen RK3568_LVDS1_MODE_EN(1) | RK3568_LVDS1_P2S_EN(1) | 412*dcebcd68SChaoyi Chen RK3568_LVDS1_DCLK_INV_SEL(1)); 413*dcebcd68SChaoyi Chen regmap_write(lvds->grf, RK3568_GRF_VO_CON0, 414*dcebcd68SChaoyi Chen RK3568_LVDS1_SELECT(lvds->format) | 415*dcebcd68SChaoyi Chen RK3568_LVDS1_MSBSEL(1)); 416*dcebcd68SChaoyi Chen } else { 417aeb5dd22SSandy Huang regmap_write(lvds->grf, RK3568_GRF_VO_CON2, 418aeb5dd22SSandy Huang RK3568_LVDS0_MODE_EN(1) | RK3568_LVDS0_P2S_EN(1) | 419aeb5dd22SSandy Huang RK3568_LVDS0_DCLK_INV_SEL(1)); 420aeb5dd22SSandy Huang regmap_write(lvds->grf, RK3568_GRF_VO_CON0, 421*dcebcd68SChaoyi Chen RK3568_LVDS0_SELECT(lvds->format) | 422*dcebcd68SChaoyi Chen RK3568_LVDS0_MSBSEL(1)); 423*dcebcd68SChaoyi Chen } 424aeb5dd22SSandy Huang } 425aeb5dd22SSandy Huang 426aeb5dd22SSandy Huang static void rk3568_lvds_disable(struct rockchip_lvds *lvds) 427aeb5dd22SSandy Huang { 428*dcebcd68SChaoyi Chen if (lvds->id) 429*dcebcd68SChaoyi Chen regmap_write(lvds->grf, RK3568_GRF_VO_CON3, 430*dcebcd68SChaoyi Chen RK3568_LVDS1_MODE_EN(0)); 431*dcebcd68SChaoyi Chen else 432*dcebcd68SChaoyi Chen regmap_write(lvds->grf, RK3568_GRF_VO_CON2, 433*dcebcd68SChaoyi Chen RK3568_LVDS0_MODE_EN(0)); 434aeb5dd22SSandy Huang } 435aeb5dd22SSandy Huang 436aeb5dd22SSandy Huang static const struct rockchip_lvds_funcs rk3568_lvds_funcs = { 437*dcebcd68SChaoyi Chen .probe = rk3568_lvds_probe, 438aeb5dd22SSandy Huang .enable = rk3568_lvds_enable, 439aeb5dd22SSandy Huang .disable = rk3568_lvds_disable, 440aeb5dd22SSandy Huang }; 441aeb5dd22SSandy Huang 442186f8572SMark Yao static const struct udevice_id rockchip_lvds_ids[] = { 443186f8572SMark Yao { 44430d6d433SWyon Bi .compatible = "rockchip,px30-lvds", 4450594ce39SZhang Yubing .data = (ulong)&px30_lvds_funcs, 44630d6d433SWyon Bi }, 44730d6d433SWyon Bi { 44830d6d433SWyon Bi .compatible = "rockchip,rk3126-lvds", 4490594ce39SZhang Yubing .data = (ulong)&rk3126_lvds_funcs, 45030d6d433SWyon Bi }, 45130d6d433SWyon Bi { 45230d6d433SWyon Bi .compatible = "rockchip,rk3288-lvds", 4530594ce39SZhang Yubing .data = (ulong)&rk3288_lvds_funcs, 45430d6d433SWyon Bi }, 45530d6d433SWyon Bi { 456186f8572SMark Yao .compatible = "rockchip,rk3368-lvds", 4570594ce39SZhang Yubing .data = (ulong)&rk3368_lvds_funcs, 45830d6d433SWyon Bi }, 459aeb5dd22SSandy Huang { 460cc341c3bSZhang Yubing .compatible = "rockchip,rk3562-lvds", 461cc341c3bSZhang Yubing .data = (ulong)&rk3562_lvds_funcs, 462cc341c3bSZhang Yubing }, 463cc341c3bSZhang Yubing { 464aeb5dd22SSandy Huang .compatible = "rockchip,rk3568-lvds", 4650594ce39SZhang Yubing .data = (ulong)&rk3568_lvds_funcs, 466aeb5dd22SSandy Huang }, 46730d6d433SWyon Bi {} 468186f8572SMark Yao }; 469186f8572SMark Yao 470186f8572SMark Yao U_BOOT_DRIVER(rockchip_lvds) = { 471186f8572SMark Yao .name = "rockchip_lvds", 472186f8572SMark Yao .id = UCLASS_DISPLAY, 473186f8572SMark Yao .of_match = rockchip_lvds_ids, 474b69d3ed4SWyon Bi .probe = rockchip_lvds_probe, 475b69d3ed4SWyon Bi .priv_auto_alloc_size = sizeof(struct rockchip_lvds), 476186f8572SMark Yao }; 477