1 /* 2 * (C) Copyright 2023 Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <asm/io.h> 9 #include <malloc.h> 10 #include <mp_boot.h> 11 #include <spl.h> 12 #include <part.h> 13 #include <drm_modes.h> 14 #include <spl_display.h> 15 #include <linux/hdmi.h> 16 17 #include "rockchip_display.h" 18 #include "rockchip_crtc.h" 19 #include "rockchip_connector.h" 20 #include "rockchip_phy.h" 21 22 static struct base2_info base_parameter; 23 24 struct display_state *rockchip_spl_display_drv_probe(void) 25 { 26 struct display_state *state = malloc(sizeof(struct display_state)); 27 if (!state) 28 return NULL; 29 30 memset(state, 0, sizeof(*state)); 31 32 rockchip_spl_vop_probe(&state->crtc_state); 33 rockchip_spl_dw_hdmi_probe(&state->conn_state); 34 inno_spl_hdmi_phy_probe(state); 35 36 return state; 37 } 38 39 static int rockchip_spl_display_init(struct display_state *state) 40 { 41 struct crtc_state *crtc_state = &state->crtc_state; 42 struct connector_state *conn_state = &state->conn_state; 43 struct rockchip_connector *conn = conn_state->connector; 44 const struct rockchip_crtc *crtc = crtc_state->crtc; 45 const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs; 46 const struct rockchip_connector_funcs *conn_funcs = conn->funcs; 47 struct drm_display_mode *mode = &state->conn_state.mode; 48 int ret = 0; 49 50 if (!crtc_funcs) { 51 printf("failed to find crtc functions\n"); 52 return -ENXIO; 53 } 54 55 if (crtc_funcs->preinit) { 56 ret = crtc_funcs->preinit(state); 57 if (ret) 58 return ret; 59 } 60 61 rockchip_display_make_crc32_table(); 62 if (conn_funcs->pre_init) { 63 ret = conn_funcs->pre_init(conn, state); 64 if (ret) 65 return ret; 66 } 67 68 if (conn_funcs->init) { 69 ret = conn_funcs->init(conn, state); 70 if (ret) 71 goto deinit; 72 } 73 74 if (conn->phy) 75 rockchip_phy_init(conn->phy); 76 77 if (conn_funcs->detect) { 78 conn->hpd = conn_funcs->detect(conn, state); 79 if (!conn->hpd) 80 goto deinit; 81 } 82 83 if (conn_funcs->get_timing) { 84 ret = conn_funcs->get_timing(conn, state); 85 if (ret) 86 goto deinit; 87 } 88 89 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); 90 if (p->flags & DRM_MODE_FLAG_DBLCLK) 91 p->crtc_clock = 2 * p->clock; 92 93 if (crtc_funcs->init) { 94 ret = crtc_funcs->init(state); 95 if (ret) 96 goto deinit; 97 } 98 99 return 0; 100 101 deinit: 102 rockchip_connector_deinit(state); 103 return ret; 104 } 105 106 static int rockchip_spl_display_post_enable(struct display_state *state) 107 { 108 struct crtc_state *crtc_state = &state->crtc_state; 109 struct connector_state *conn_state = &state->conn_state; 110 struct rockchip_connector *conn = conn_state->connector; 111 const struct rockchip_crtc *crtc = crtc_state->crtc; 112 const struct rockchip_crtc_funcs *crtc_funcs = crtc->funcs; 113 const struct rockchip_connector_funcs *conn_funcs = conn->funcs; 114 115 if (crtc_funcs->enable) 116 crtc_funcs->enable(state); 117 state->crtc_state.crtc->active = true; 118 119 if (conn_funcs->enable) 120 conn_funcs->enable(conn, state); 121 122 return 0; 123 } 124 125 static void rockchip_spl_display_transmit_info_to_uboot(struct display_state *state) 126 { 127 struct connector_state *conn_state = &state->conn_state; 128 struct spl_display_info *spl_disp_info = (struct spl_display_info *)CONFIG_SPL_VIDEO_BUF; 129 130 /* transmit mode and bus_format to uboot */ 131 memcpy(&spl_disp_info->mode, &conn_state->mode, sizeof(conn_state->mode)); 132 spl_disp_info->bus_format = state->conn_state.bus_format; 133 spl_disp_info->enabled = 1; 134 flush_dcache_all(); 135 } 136 137 int spl_init_display(struct task_data *data) 138 { 139 struct display_state *state = NULL; 140 struct drm_display_mode *mode; 141 int ret = 0; 142 143 state = rockchip_spl_display_drv_probe(); 144 if (!state) { 145 printf("rockchip_spl_display_drv_probe failed\n"); 146 return -1; 147 } 148 149 ret = rockchip_spl_display_init(state); 150 if (ret) { 151 printf("rockchip_spl_display_init failed ret:%d\n", ret); 152 return -1; 153 } 154 155 if (!state->conn_state.connector->hpd) { 156 printf("HDMI is unplug and exit\n"); 157 return 0; 158 } 159 160 ret = rockchip_spl_display_post_enable(state); 161 if (ret) { 162 printf("rockchip_spl_display_post_enable failed ret:%d\n", ret); 163 return -1; 164 } 165 166 rockchip_spl_display_transmit_info_to_uboot(state); 167 168 mode = &state->conn_state.mode; 169 printf("SPL enable hdmi, detailed mode clock %u kHz, flags[%x]\n" 170 " H: %04d %04d %04d %04d\n" 171 " V: %04d %04d %04d %04d\n" 172 "bus_format: %x\n", 173 mode->clock, mode->flags, 174 mode->hdisplay, mode->hsync_start, 175 mode->hsync_end, mode->htotal, 176 mode->vdisplay, mode->vsync_start, 177 mode->vsync_end, mode->vtotal, 178 state->conn_state.bus_format); 179 180 return ret; 181 } 182 183 struct base2_disp_info *rockchip_get_disp_info(int type, int id) 184 { 185 struct base2_disp_info *disp_info; 186 struct base2_disp_header *disp_header; 187 int i = 0, offset = -1; 188 u32 crc_val; 189 u32 base2_length; 190 void *base_parameter_addr = (void *)&base_parameter; 191 #ifdef CONFIG_MP_BOOT 192 void *bp_addr = (void *)CONFIG_SPL_VIDEO_BUF; 193 ulong ret; 194 195 /* make sure the baseparameter is ready */ 196 ret = mpb_post(6); 197 printf("SPL read baseparameter %s\n", ret < 0 ? "failed" : "success"); 198 memcpy(&base_parameter, bp_addr, sizeof(base_parameter)); 199 #endif 200 for (i = 0; i < 8; i++) { 201 disp_header = &base_parameter.disp_header[i]; 202 if (disp_header->connector_type == type && 203 disp_header->connector_id == id) { 204 printf("disp info %d, type:%d, id:%d\n", i, type, id); 205 offset = disp_header->offset; 206 break; 207 } 208 } 209 210 if (offset < 0) 211 return NULL; 212 disp_info = base_parameter_addr + offset; 213 if (disp_info->screen_info[0].type != type || 214 disp_info->screen_info[0].id != id) { 215 printf("base2_disp_info couldn't be found, screen_info type[%d] or id[%d] mismatched\n", 216 disp_info->screen_info[0].type, 217 disp_info->screen_info[0].id); 218 return NULL; 219 } 220 221 if (strncasecmp(disp_info->disp_head_flag, "DISP", 4)) 222 return NULL; 223 224 if (base_parameter.major_version == 3 && base_parameter.minor_version == 0) { 225 crc_val = rockchip_display_crc32c_cal((unsigned char *)disp_info, 226 sizeof(struct base2_disp_info) - 4); 227 if (crc_val != disp_info->crc2) { 228 printf("error: connector type[%d], id[%d] disp info crc2 check error\n", 229 type, id); 230 return NULL; 231 } 232 } else { 233 base2_length = sizeof(struct base2_disp_info) - sizeof(struct csc_info) - 234 sizeof(struct acm_data) - 10 * 1024 - 4; 235 crc_val = rockchip_display_crc32c_cal((unsigned char *)disp_info, base2_length - 4); 236 if (crc_val != disp_info->crc) { 237 printf("error: connector type[%d], id[%d] disp info crc check error\n", 238 type, id); 239 return NULL; 240 } 241 } 242 243 return disp_info; 244 } 245 246 int spl_load_baseparamter(struct task_data *data) 247 { 248 struct spl_load_info *info = &data->info; 249 ulong addr = CONFIG_SPL_VIDEO_BUF; 250 disk_partition_t part; 251 252 debug("== Baseparam: start\n"); 253 254 if (part_get_info_by_name(info->dev, "baseparameter", &part) < 0) { 255 printf("No baseparameter partition\n"); 256 return -ENOENT; 257 } else { 258 if (info->read(info, part.start, part.size, (void *)addr) != part.size) 259 return -EIO; 260 else 261 flush_dcache_range(addr, addr + part.size * info->bl_len); 262 } 263 264 debug("== Baseparam: load OK\n"); 265 266 return 0; 267 } 268 269