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