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 <dm/of_access.h> 9 #include <errno.h> 10 #include <syscon.h> 11 #include <regmap.h> 12 #include <dm/device.h> 13 #include <dm/read.h> 14 #include <dm/pinctrl.h> 15 #include <linux/media-bus-format.h> 16 17 #include "rockchip_display.h" 18 #include "rockchip_crtc.h" 19 #include "rockchip_connector.h" 20 #include "rockchip_phy.h" 21 22 #define HIWORD_UPDATE(v, h, l) (((v) << (l)) | (GENMASK(h, l) << 16)) 23 24 #define PX30_GRF_PD_VO_CON1 0x0438 25 #define PX30_RGB_DATA_SYNC_BYPASS(v) HIWORD_UPDATE(v, 3, 3) 26 #define PX30_RGB_VOP_SEL(v) HIWORD_UPDATE(v, 2, 2) 27 28 #define RK1808_GRF_PD_VO_CON1 0x0444 29 #define RK1808_RGB_DATA_SYNC_BYPASS(v) HIWORD_UPDATE(v, 3, 3) 30 31 #define RV1126_GRF_IOFUNC_CON3 0x1026c 32 #define RV1126_LCDC_IO_BYPASS(v) HIWORD_UPDATE(v, 0, 0) 33 34 #define RK3288_GRF_SOC_CON6 0x025c 35 #define RK3288_LVDS_LCDC_SEL(v) HIWORD_UPDATE(v, 3, 3) 36 #define RK3288_GRF_SOC_CON7 0x0260 37 #define RK3288_LVDS_PWRDWN(v) HIWORD_UPDATE(v, 15, 15) 38 #define RK3288_LVDS_CON_ENABLE_2(v) HIWORD_UPDATE(v, 12, 12) 39 #define RK3288_LVDS_CON_ENABLE_1(v) HIWORD_UPDATE(v, 11, 11) 40 #define RK3288_LVDS_CON_CLKINV(v) HIWORD_UPDATE(v, 8, 8) 41 #define RK3288_LVDS_CON_TTL_EN(v) HIWORD_UPDATE(v, 6, 6) 42 43 #define RK3368_GRF_SOC_CON15 0x043c 44 #define RK3368_FORCE_JETAG(v) HIWORD_UPDATE(v, 13, 13) 45 46 #define RK3568_GRF_VO_CON1 0X0364 47 #define RK3568_RGB_DATA_BYPASS(v) HIWORD_UPDATE(v, 6, 6) 48 49 struct rockchip_rgb; 50 51 struct rockchip_rgb_funcs { 52 void (*prepare)(struct rockchip_rgb *rgb, int pipe); 53 void (*unprepare)(struct rockchip_rgb *rgb); 54 }; 55 56 struct rockchip_rgb { 57 int id; 58 struct udevice *dev; 59 struct regmap *grf; 60 bool data_sync_bypass; 61 struct rockchip_phy *phy; 62 const struct rockchip_rgb_funcs *funcs; 63 }; 64 65 static inline struct rockchip_rgb *state_to_rgb(struct display_state *state) 66 { 67 struct connector_state *conn_state = &state->conn_state; 68 69 return dev_get_priv(conn_state->dev); 70 } 71 72 static int rockchip_rgb_connector_prepare(struct display_state *state) 73 { 74 struct rockchip_rgb *rgb = state_to_rgb(state); 75 struct crtc_state *crtc_state = &state->crtc_state; 76 int pipe = crtc_state->crtc_id; 77 int ret; 78 79 pinctrl_select_state(rgb->dev, "default"); 80 81 if (rgb->funcs && rgb->funcs->prepare) 82 rgb->funcs->prepare(rgb, pipe); 83 84 if (rgb->phy) { 85 ret = rockchip_phy_set_mode(rgb->phy, PHY_MODE_VIDEO_TTL); 86 if (ret) { 87 dev_err(rgb->dev, "failed to set phy mode: %d\n", ret); 88 return ret; 89 } 90 91 rockchip_phy_power_on(rgb->phy); 92 } 93 94 return 0; 95 } 96 97 static void rockchip_rgb_connector_unprepare(struct display_state *state) 98 { 99 struct rockchip_rgb *rgb = state_to_rgb(state); 100 101 if (rgb->phy) 102 rockchip_phy_power_off(rgb->phy); 103 104 if (rgb->funcs && rgb->funcs->unprepare) 105 rgb->funcs->unprepare(rgb); 106 107 pinctrl_select_state(rgb->dev, "sleep"); 108 } 109 110 static int rockchip_rgb_connector_pre_init(struct display_state *state) 111 { 112 struct connector_state *conn_state = &state->conn_state; 113 114 conn_state->type = DRM_MODE_CONNECTOR_LVDS; 115 116 return 0; 117 } 118 119 static int rockchip_rgb_connector_init(struct display_state *state) 120 { 121 struct rockchip_rgb *rgb = state_to_rgb(state); 122 struct connector_state *conn_state = &state->conn_state; 123 124 rgb->phy = conn_state->phy; 125 126 conn_state->color_space = V4L2_COLORSPACE_DEFAULT; 127 conn_state->disp_info = rockchip_get_disp_info(conn_state->type, rgb->id); 128 129 switch (conn_state->bus_format) { 130 case MEDIA_BUS_FMT_RGB666_1X18: 131 conn_state->output_mode = ROCKCHIP_OUT_MODE_P666; 132 conn_state->output_if = VOP_OUTPUT_IF_RGB; 133 break; 134 case MEDIA_BUS_FMT_RGB565_1X16: 135 conn_state->output_mode = ROCKCHIP_OUT_MODE_P565; 136 conn_state->output_if = VOP_OUTPUT_IF_RGB; 137 break; 138 case MEDIA_BUS_FMT_SRGB888_3X8: 139 case MEDIA_BUS_FMT_SBGR888_3X8: 140 case MEDIA_BUS_FMT_SRBG888_3X8: 141 conn_state->output_mode = ROCKCHIP_OUT_MODE_S888; 142 conn_state->output_if = VOP_OUTPUT_IF_RGB; 143 break; 144 case MEDIA_BUS_FMT_SRGB888_DUMMY_4X8: 145 case MEDIA_BUS_FMT_SBGR888_DUMMY_4X8: 146 case MEDIA_BUS_FMT_SRBG888_DUMMY_4X8: 147 conn_state->output_mode = ROCKCHIP_OUT_MODE_S888_DUMMY; 148 conn_state->output_if = VOP_OUTPUT_IF_RGB; 149 break; 150 case MEDIA_BUS_FMT_YUYV8_2X8: 151 case MEDIA_BUS_FMT_YVYU8_2X8: 152 case MEDIA_BUS_FMT_UYVY8_2X8: 153 case MEDIA_BUS_FMT_VYUY8_2X8: 154 conn_state->output_mode = ROCKCHIP_OUT_MODE_BT656; 155 conn_state->output_if = VOP_OUTPUT_IF_BT656; 156 break; 157 case MEDIA_BUS_FMT_YUYV8_1X16: 158 case MEDIA_BUS_FMT_YVYU8_1X16: 159 case MEDIA_BUS_FMT_UYVY8_1X16: 160 case MEDIA_BUS_FMT_VYUY8_1X16: 161 conn_state->output_mode = ROCKCHIP_OUT_MODE_BT1120; 162 conn_state->output_if = VOP_OUTPUT_IF_BT1120; 163 case MEDIA_BUS_FMT_RGB888_1X24: 164 case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: 165 default: 166 conn_state->output_mode = ROCKCHIP_OUT_MODE_P888; 167 conn_state->output_if = VOP_OUTPUT_IF_RGB; 168 break; 169 } 170 171 return 0; 172 } 173 174 static const struct rockchip_connector_funcs rockchip_rgb_connector_funcs = { 175 .pre_init = rockchip_rgb_connector_pre_init, 176 .init = rockchip_rgb_connector_init, 177 .prepare = rockchip_rgb_connector_prepare, 178 .unprepare = rockchip_rgb_connector_unprepare, 179 }; 180 181 static int rockchip_rgb_probe(struct udevice *dev) 182 { 183 struct rockchip_rgb *rgb = dev_get_priv(dev); 184 const struct rockchip_connector *connector = 185 (const struct rockchip_connector *)dev_get_driver_data(dev); 186 187 rgb->dev = dev; 188 rgb->funcs = connector->data; 189 rgb->grf = syscon_get_regmap(dev_get_parent(dev)); 190 rgb->data_sync_bypass = dev_read_bool(dev, "rockchip,data-sync-bypass"); 191 rgb->id = of_alias_get_id(ofnode_to_np(dev->node), "rgb"); 192 if (rgb->id < 0) 193 rgb->id = 0; 194 195 return 0; 196 } 197 198 static void rv1126_rgb_prepare(struct rockchip_rgb *rgb, int pipe) 199 { 200 regmap_write(rgb->grf, RV1126_GRF_IOFUNC_CON3, 201 RV1126_LCDC_IO_BYPASS(rgb->data_sync_bypass)); 202 } 203 204 static const struct rockchip_rgb_funcs rv1126_rgb_funcs = { 205 .prepare = rv1126_rgb_prepare, 206 }; 207 208 static const struct rockchip_connector rv1126_rgb_driver_data = { 209 .funcs = &rockchip_rgb_connector_funcs, 210 .data = &rv1126_rgb_funcs, 211 }; 212 213 static void px30_rgb_prepare(struct rockchip_rgb *rgb, int pipe) 214 { 215 regmap_write(rgb->grf, PX30_GRF_PD_VO_CON1, PX30_RGB_VOP_SEL(pipe) | 216 PX30_RGB_DATA_SYNC_BYPASS(rgb->data_sync_bypass)); 217 } 218 219 static const struct rockchip_rgb_funcs px30_rgb_funcs = { 220 .prepare = px30_rgb_prepare, 221 }; 222 223 static const struct rockchip_connector px30_rgb_driver_data = { 224 .funcs = &rockchip_rgb_connector_funcs, 225 .data = &px30_rgb_funcs, 226 }; 227 228 static void rk1808_rgb_prepare(struct rockchip_rgb *rgb, int pipe) 229 { 230 regmap_write(rgb->grf, RK1808_GRF_PD_VO_CON1, 231 RK1808_RGB_DATA_SYNC_BYPASS(rgb->data_sync_bypass)); 232 } 233 234 static const struct rockchip_rgb_funcs rk1808_rgb_funcs = { 235 .prepare = rk1808_rgb_prepare, 236 }; 237 238 static const struct rockchip_connector rk1808_rgb_driver_data = { 239 .funcs = &rockchip_rgb_connector_funcs, 240 .data = &rk1808_rgb_funcs, 241 }; 242 243 static void rk3288_rgb_prepare(struct rockchip_rgb *rgb, int pipe) 244 { 245 regmap_write(rgb->grf, RK3288_GRF_SOC_CON6, RK3288_LVDS_LCDC_SEL(pipe)); 246 regmap_write(rgb->grf, RK3288_GRF_SOC_CON7, 247 RK3288_LVDS_PWRDWN(0) | RK3288_LVDS_CON_ENABLE_2(1) | 248 RK3288_LVDS_CON_ENABLE_1(1) | RK3288_LVDS_CON_CLKINV(0) | 249 RK3288_LVDS_CON_TTL_EN(1)); 250 } 251 252 static void rk3288_rgb_unprepare(struct rockchip_rgb *rgb) 253 { 254 regmap_write(rgb->grf, RK3288_GRF_SOC_CON7, 255 RK3288_LVDS_PWRDWN(1) | RK3288_LVDS_CON_ENABLE_2(0) | 256 RK3288_LVDS_CON_ENABLE_1(0) | RK3288_LVDS_CON_TTL_EN(0)); 257 } 258 259 static const struct rockchip_rgb_funcs rk3288_rgb_funcs = { 260 .prepare = rk3288_rgb_prepare, 261 .unprepare = rk3288_rgb_unprepare, 262 }; 263 264 static const struct rockchip_connector rk3288_rgb_driver_data = { 265 .funcs = &rockchip_rgb_connector_funcs, 266 .data = &rk3288_rgb_funcs, 267 }; 268 269 static void rk3368_rgb_prepare(struct rockchip_rgb *rgb, int pipe) 270 { 271 regmap_write(rgb->grf, RK3368_GRF_SOC_CON15, RK3368_FORCE_JETAG(0)); 272 } 273 274 static const struct rockchip_rgb_funcs rk3368_rgb_funcs = { 275 .prepare = rk3368_rgb_prepare, 276 }; 277 278 static const struct rockchip_connector rk3368_rgb_driver_data = { 279 .funcs = &rockchip_rgb_connector_funcs, 280 .data = &rk3368_rgb_funcs, 281 }; 282 283 static void rk3568_rgb_prepare(struct rockchip_rgb *rgb, int pipe) 284 { 285 regmap_write(rgb->grf, RK3568_GRF_VO_CON1, RK3568_RGB_DATA_BYPASS(0)); 286 } 287 288 static const struct rockchip_rgb_funcs rk3568_rgb_funcs = { 289 .prepare = rk3568_rgb_prepare, 290 }; 291 292 static const struct rockchip_connector rk3568_rgb_driver_data = { 293 .funcs = &rockchip_rgb_connector_funcs, 294 .data = &rk3568_rgb_funcs, 295 }; 296 297 static const struct rockchip_connector rockchip_rgb_driver_data = { 298 .funcs = &rockchip_rgb_connector_funcs, 299 }; 300 301 static const struct udevice_id rockchip_rgb_ids[] = { 302 { 303 .compatible = "rockchip,px30-rgb", 304 .data = (ulong)&px30_rgb_driver_data, 305 }, 306 { 307 .compatible = "rockchip,rk1808-rgb", 308 .data = (ulong)&rk1808_rgb_driver_data, 309 }, 310 { 311 .compatible = "rockchip,rk3066-rgb", 312 .data = (ulong)&rockchip_rgb_driver_data, 313 }, 314 { 315 .compatible = "rockchip,rk3128-rgb", 316 .data = (ulong)&rockchip_rgb_driver_data, 317 }, 318 { 319 .compatible = "rockchip,rk3288-rgb", 320 .data = (ulong)&rk3288_rgb_driver_data, 321 }, 322 { 323 .compatible = "rockchip,rk3308-rgb", 324 .data = (ulong)&rockchip_rgb_driver_data, 325 }, 326 { 327 .compatible = "rockchip,rk3368-rgb", 328 .data = (ulong)&rk3368_rgb_driver_data, 329 }, 330 { 331 .compatible = "rockchip,rk3568-rgb", 332 .data = (ulong)&rk3568_rgb_driver_data, 333 }, 334 { 335 .compatible = "rockchip,rv1108-rgb", 336 .data = (ulong)&rockchip_rgb_driver_data, 337 }, 338 { 339 .compatible = "rockchip,rv1126-rgb", 340 .data = (ulong)&rv1126_rgb_driver_data, 341 }, 342 {} 343 }; 344 345 U_BOOT_DRIVER(rockchip_rgb) = { 346 .name = "rockchip_rgb", 347 .id = UCLASS_DISPLAY, 348 .of_match = rockchip_rgb_ids, 349 .probe = rockchip_rgb_probe, 350 .priv_auto_alloc_size = sizeof(struct rockchip_rgb), 351 }; 352