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