1 /* 2 * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <errno.h> 9 #include <syscon.h> 10 #include <regmap.h> 11 #include <dm/device.h> 12 #include <dm/read.h> 13 #include <linux/media-bus-format.h> 14 15 #include "rockchip_display.h" 16 #include "rockchip_crtc.h" 17 #include "rockchip_connector.h" 18 #include "rockchip_phy.h" 19 20 #define PX30_GRF_PD_VO_CON1 0x0438 21 #define PX30_RGB_DATA_SYNC_BYPASS(v) HIWORD_UPDATE(v, 3, 3) 22 #define PX30_RGB_VOP_SEL(v) HIWORD_UPDATE(v, 2, 2) 23 24 #define RK1808_GRF_PD_VO_CON1 0x0444 25 #define RK1808_RGB_DATA_SYNC_BYPASS(v) HIWORD_UPDATE(v, 3, 3) 26 27 #define RK3288_GRF_SOC_CON6 0x025c 28 #define RK3288_LVDS_LCDC_SEL(v) HIWORD_UPDATE(v, 3, 3) 29 #define RK3288_GRF_SOC_CON7 0x0260 30 #define RK3288_LVDS_PWRDWN(v) HIWORD_UPDATE(v, 15, 15) 31 #define RK3288_LVDS_CON_ENABLE_2(v) HIWORD_UPDATE(v, 12, 12) 32 #define RK3288_LVDS_CON_ENABLE_1(v) HIWORD_UPDATE(v, 11, 11) 33 #define RK3288_LVDS_CON_CLKINV(v) HIWORD_UPDATE(v, 8, 8) 34 #define RK3288_LVDS_CON_TTL_EN(v) HIWORD_UPDATE(v, 6, 6) 35 36 struct rockchip_rgb; 37 38 struct rockchip_rgb_funcs { 39 void (*enable)(struct rockchip_rgb *rgb, int pipe); 40 void (*disable)(struct rockchip_rgb *rgb); 41 }; 42 43 struct rockchip_rgb { 44 struct udevice *dev; 45 struct regmap *grf; 46 bool data_sync; 47 struct rockchip_phy *phy; 48 const struct rockchip_rgb_funcs *funcs; 49 }; 50 51 static inline struct rockchip_rgb *state_to_rgb(struct display_state *state) 52 { 53 struct connector_state *conn_state = &state->conn_state; 54 55 return dev_get_priv(conn_state->dev); 56 } 57 58 static int rockchip_rgb_connector_enable(struct display_state *state) 59 { 60 struct rockchip_rgb *rgb = state_to_rgb(state); 61 struct crtc_state *crtc_state = &state->crtc_state; 62 int pipe = crtc_state->crtc_id; 63 int ret; 64 65 if (rgb->funcs && rgb->funcs->enable) 66 rgb->funcs->enable(rgb, pipe); 67 68 if (rgb->phy) { 69 ret = rockchip_phy_set_mode(rgb->phy, PHY_MODE_VIDEO_TTL); 70 if (ret) { 71 dev_err(rgb->dev, "failed to set phy mode: %d\n", ret); 72 return ret; 73 } 74 75 rockchip_phy_power_on(rgb->phy); 76 } 77 78 return 0; 79 } 80 81 static int rockchip_rgb_connector_disable(struct display_state *state) 82 { 83 struct rockchip_rgb *rgb = state_to_rgb(state); 84 85 if (rgb->phy) 86 rockchip_phy_power_off(rgb->phy); 87 88 if (rgb->funcs && rgb->funcs->disable) 89 rgb->funcs->disable(rgb); 90 91 return 0; 92 } 93 94 static int rockchip_rgb_connector_init(struct display_state *state) 95 { 96 struct rockchip_rgb *rgb = state_to_rgb(state); 97 struct connector_state *conn_state = &state->conn_state; 98 99 rgb->phy = conn_state->phy; 100 101 conn_state->type = DRM_MODE_CONNECTOR_LVDS; 102 conn_state->color_space = V4L2_COLORSPACE_DEFAULT; 103 104 switch (conn_state->bus_format) { 105 case MEDIA_BUS_FMT_RGB666_1X18: 106 conn_state->output_mode = ROCKCHIP_OUT_MODE_P666; 107 break; 108 case MEDIA_BUS_FMT_RGB565_1X16: 109 conn_state->output_mode = ROCKCHIP_OUT_MODE_P565; 110 break; 111 case MEDIA_BUS_FMT_RGB888_1X24: 112 case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: 113 default: 114 conn_state->output_mode = ROCKCHIP_OUT_MODE_P888; 115 break; 116 } 117 118 return 0; 119 } 120 121 static const struct rockchip_connector_funcs rockchip_rgb_connector_funcs = { 122 .init = rockchip_rgb_connector_init, 123 .enable = rockchip_rgb_connector_enable, 124 .disable = rockchip_rgb_connector_disable, 125 }; 126 127 static int rockchip_rgb_probe(struct udevice *dev) 128 { 129 struct rockchip_rgb *rgb = dev_get_priv(dev); 130 const struct rockchip_connector *connector = 131 (const struct rockchip_connector *)dev_get_driver_data(dev); 132 133 rgb->dev = dev; 134 rgb->funcs = connector->data; 135 rgb->grf = syscon_get_regmap(dev_get_parent(dev)); 136 rgb->data_sync = dev_read_bool(dev, "rockchip,data-sync"); 137 138 return 0; 139 } 140 141 static void px30_rgb_enable(struct rockchip_rgb *rgb, int pipe) 142 { 143 regmap_write(rgb->grf, PX30_GRF_PD_VO_CON1, PX30_RGB_VOP_SEL(pipe) | 144 PX30_RGB_DATA_SYNC_BYPASS(!rgb->data_sync)); 145 } 146 147 static const struct rockchip_rgb_funcs px30_rgb_funcs = { 148 .enable = px30_rgb_enable, 149 }; 150 151 static const struct rockchip_connector px30_rgb_driver_data = { 152 .funcs = &rockchip_rgb_connector_funcs, 153 .data = &px30_rgb_funcs, 154 }; 155 156 static void rk1808_rgb_enable(struct rockchip_rgb *rgb, int pipe) 157 { 158 regmap_write(rgb->grf, RK1808_GRF_PD_VO_CON1, 159 RK1808_RGB_DATA_SYNC_BYPASS(!rgb->data_sync)); 160 } 161 162 static const struct rockchip_rgb_funcs rk1808_rgb_funcs = { 163 .enable = rk1808_rgb_enable, 164 }; 165 166 static const struct rockchip_connector rk1808_rgb_driver_data = { 167 .funcs = &rockchip_rgb_connector_funcs, 168 .data = &rk1808_rgb_funcs, 169 }; 170 171 static void rk3288_rgb_enable(struct rockchip_rgb *rgb, int pipe) 172 { 173 regmap_write(rgb->grf, RK3288_GRF_SOC_CON6, RK3288_LVDS_LCDC_SEL(pipe)); 174 regmap_write(rgb->grf, RK3288_GRF_SOC_CON7, 175 RK3288_LVDS_PWRDWN(0) | RK3288_LVDS_CON_ENABLE_2(1) | 176 RK3288_LVDS_CON_ENABLE_1(1) | RK3288_LVDS_CON_CLKINV(0) | 177 RK3288_LVDS_CON_TTL_EN(1)); 178 } 179 180 static void rk3288_rgb_disable(struct rockchip_rgb *rgb) 181 { 182 regmap_write(rgb->grf, RK3288_GRF_SOC_CON7, 183 RK3288_LVDS_PWRDWN(1) | RK3288_LVDS_CON_ENABLE_2(0) | 184 RK3288_LVDS_CON_ENABLE_1(0) | RK3288_LVDS_CON_TTL_EN(0)); 185 } 186 187 static const struct rockchip_rgb_funcs rk3288_rgb_funcs = { 188 .enable = rk3288_rgb_enable, 189 .disable = rk3288_rgb_disable, 190 }; 191 192 static const struct rockchip_connector rk3288_rgb_driver_data = { 193 .funcs = &rockchip_rgb_connector_funcs, 194 .data = &rk3288_rgb_funcs, 195 }; 196 197 static const struct rockchip_connector rockchip_rgb_driver_data = { 198 .funcs = &rockchip_rgb_connector_funcs, 199 }; 200 201 static const struct udevice_id rockchip_rgb_ids[] = { 202 { 203 .compatible = "rockchip,px30-rgb", 204 .data = (ulong)&px30_rgb_driver_data, 205 }, 206 { 207 .compatible = "rockchip,rk1808-rgb", 208 .data = (ulong)&rk1808_rgb_driver_data, 209 }, 210 { 211 .compatible = "rockchip,rk3066-rgb", 212 .data = (ulong)&rockchip_rgb_driver_data, 213 }, 214 { 215 .compatible = "rockchip,rk3128-rgb", 216 .data = (ulong)&rockchip_rgb_driver_data, 217 }, 218 { 219 .compatible = "rockchip,rk3288-rgb", 220 .data = (ulong)&rk3288_rgb_driver_data, 221 }, 222 { 223 .compatible = "rockchip,rk3308-rgb", 224 .data = (ulong)&rockchip_rgb_driver_data, 225 }, 226 { 227 .compatible = "rockchip,rk3368-rgb", 228 .data = (ulong)&rockchip_rgb_driver_data, 229 }, 230 { 231 .compatible = "rockchip,rv1108-rgb", 232 .data = (ulong)&rockchip_rgb_driver_data, 233 }, 234 {} 235 }; 236 237 U_BOOT_DRIVER(rockchip_rgb) = { 238 .name = "rockchip_rgb", 239 .id = UCLASS_DISPLAY, 240 .of_match = rockchip_rgb_ids, 241 .probe = rockchip_rgb_probe, 242 .priv_auto_alloc_size = sizeof(struct rockchip_rgb), 243 }; 244