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 break; 164 case MEDIA_BUS_FMT_RGB888_1X24: 165 case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: 166 default: 167 conn_state->output_mode = ROCKCHIP_OUT_MODE_P888; 168 conn_state->output_if = VOP_OUTPUT_IF_RGB; 169 break; 170 } 171 172 return 0; 173 } 174 175 static const struct rockchip_connector_funcs rockchip_rgb_connector_funcs = { 176 .pre_init = rockchip_rgb_connector_pre_init, 177 .init = rockchip_rgb_connector_init, 178 .prepare = rockchip_rgb_connector_prepare, 179 .unprepare = rockchip_rgb_connector_unprepare, 180 }; 181 182 static int rockchip_rgb_probe(struct udevice *dev) 183 { 184 struct rockchip_rgb *rgb = dev_get_priv(dev); 185 const struct rockchip_connector *connector = 186 (const struct rockchip_connector *)dev_get_driver_data(dev); 187 188 rgb->dev = dev; 189 rgb->funcs = connector->data; 190 rgb->grf = syscon_get_regmap(dev_get_parent(dev)); 191 rgb->data_sync_bypass = dev_read_bool(dev, "rockchip,data-sync-bypass"); 192 rgb->id = of_alias_get_id(ofnode_to_np(dev->node), "rgb"); 193 if (rgb->id < 0) 194 rgb->id = 0; 195 196 return 0; 197 } 198 199 static void rv1126_rgb_prepare(struct rockchip_rgb *rgb, int pipe) 200 { 201 regmap_write(rgb->grf, RV1126_GRF_IOFUNC_CON3, 202 RV1126_LCDC_IO_BYPASS(rgb->data_sync_bypass)); 203 } 204 205 static const struct rockchip_rgb_funcs rv1126_rgb_funcs = { 206 .prepare = rv1126_rgb_prepare, 207 }; 208 209 static const struct rockchip_connector rv1126_rgb_driver_data = { 210 .funcs = &rockchip_rgb_connector_funcs, 211 .data = &rv1126_rgb_funcs, 212 }; 213 214 static void px30_rgb_prepare(struct rockchip_rgb *rgb, int pipe) 215 { 216 regmap_write(rgb->grf, PX30_GRF_PD_VO_CON1, PX30_RGB_VOP_SEL(pipe) | 217 PX30_RGB_DATA_SYNC_BYPASS(rgb->data_sync_bypass)); 218 } 219 220 static const struct rockchip_rgb_funcs px30_rgb_funcs = { 221 .prepare = px30_rgb_prepare, 222 }; 223 224 static const struct rockchip_connector px30_rgb_driver_data = { 225 .funcs = &rockchip_rgb_connector_funcs, 226 .data = &px30_rgb_funcs, 227 }; 228 229 static void rk1808_rgb_prepare(struct rockchip_rgb *rgb, int pipe) 230 { 231 regmap_write(rgb->grf, RK1808_GRF_PD_VO_CON1, 232 RK1808_RGB_DATA_SYNC_BYPASS(rgb->data_sync_bypass)); 233 } 234 235 static const struct rockchip_rgb_funcs rk1808_rgb_funcs = { 236 .prepare = rk1808_rgb_prepare, 237 }; 238 239 static const struct rockchip_connector rk1808_rgb_driver_data = { 240 .funcs = &rockchip_rgb_connector_funcs, 241 .data = &rk1808_rgb_funcs, 242 }; 243 244 static void rk3288_rgb_prepare(struct rockchip_rgb *rgb, int pipe) 245 { 246 regmap_write(rgb->grf, RK3288_GRF_SOC_CON6, RK3288_LVDS_LCDC_SEL(pipe)); 247 regmap_write(rgb->grf, RK3288_GRF_SOC_CON7, 248 RK3288_LVDS_PWRDWN(0) | RK3288_LVDS_CON_ENABLE_2(1) | 249 RK3288_LVDS_CON_ENABLE_1(1) | RK3288_LVDS_CON_CLKINV(0) | 250 RK3288_LVDS_CON_TTL_EN(1)); 251 } 252 253 static void rk3288_rgb_unprepare(struct rockchip_rgb *rgb) 254 { 255 regmap_write(rgb->grf, RK3288_GRF_SOC_CON7, 256 RK3288_LVDS_PWRDWN(1) | RK3288_LVDS_CON_ENABLE_2(0) | 257 RK3288_LVDS_CON_ENABLE_1(0) | RK3288_LVDS_CON_TTL_EN(0)); 258 } 259 260 static const struct rockchip_rgb_funcs rk3288_rgb_funcs = { 261 .prepare = rk3288_rgb_prepare, 262 .unprepare = rk3288_rgb_unprepare, 263 }; 264 265 static const struct rockchip_connector rk3288_rgb_driver_data = { 266 .funcs = &rockchip_rgb_connector_funcs, 267 .data = &rk3288_rgb_funcs, 268 }; 269 270 static void rk3368_rgb_prepare(struct rockchip_rgb *rgb, int pipe) 271 { 272 regmap_write(rgb->grf, RK3368_GRF_SOC_CON15, RK3368_FORCE_JETAG(0)); 273 } 274 275 static const struct rockchip_rgb_funcs rk3368_rgb_funcs = { 276 .prepare = rk3368_rgb_prepare, 277 }; 278 279 static const struct rockchip_connector rk3368_rgb_driver_data = { 280 .funcs = &rockchip_rgb_connector_funcs, 281 .data = &rk3368_rgb_funcs, 282 }; 283 284 static void rk3568_rgb_prepare(struct rockchip_rgb *rgb, int pipe) 285 { 286 regmap_write(rgb->grf, RK3568_GRF_VO_CON1, RK3568_RGB_DATA_BYPASS(rgb->data_sync_bypass)); 287 } 288 289 static const struct rockchip_rgb_funcs rk3568_rgb_funcs = { 290 .prepare = rk3568_rgb_prepare, 291 }; 292 293 static const struct rockchip_connector rk3568_rgb_driver_data = { 294 .funcs = &rockchip_rgb_connector_funcs, 295 .data = &rk3568_rgb_funcs, 296 }; 297 298 static const struct rockchip_connector rockchip_rgb_driver_data = { 299 .funcs = &rockchip_rgb_connector_funcs, 300 }; 301 302 static const struct udevice_id rockchip_rgb_ids[] = { 303 { 304 .compatible = "rockchip,px30-rgb", 305 .data = (ulong)&px30_rgb_driver_data, 306 }, 307 { 308 .compatible = "rockchip,rk1808-rgb", 309 .data = (ulong)&rk1808_rgb_driver_data, 310 }, 311 { 312 .compatible = "rockchip,rk3066-rgb", 313 .data = (ulong)&rockchip_rgb_driver_data, 314 }, 315 { 316 .compatible = "rockchip,rk3128-rgb", 317 .data = (ulong)&rockchip_rgb_driver_data, 318 }, 319 { 320 .compatible = "rockchip,rk3288-rgb", 321 .data = (ulong)&rk3288_rgb_driver_data, 322 }, 323 { 324 .compatible = "rockchip,rk3308-rgb", 325 .data = (ulong)&rockchip_rgb_driver_data, 326 }, 327 { 328 .compatible = "rockchip,rk3368-rgb", 329 .data = (ulong)&rk3368_rgb_driver_data, 330 }, 331 { 332 .compatible = "rockchip,rk3568-rgb", 333 .data = (ulong)&rk3568_rgb_driver_data, 334 }, 335 { 336 .compatible = "rockchip,rv1108-rgb", 337 .data = (ulong)&rockchip_rgb_driver_data, 338 }, 339 { 340 .compatible = "rockchip,rv1126-rgb", 341 .data = (ulong)&rv1126_rgb_driver_data, 342 }, 343 {} 344 }; 345 346 U_BOOT_DRIVER(rockchip_rgb) = { 347 .name = "rockchip_rgb", 348 .id = UCLASS_DISPLAY, 349 .of_match = rockchip_rgb_ids, 350 .probe = rockchip_rgb_probe, 351 .priv_auto_alloc_size = sizeof(struct rockchip_rgb), 352 }; 353