blob: 844496d7a0defd1bf35562ebf6264d9d4e5ee804 [file] [log] [blame]
Tristan Shiehbb684e02018-06-19 16:07:54 +08001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2018 MediaTek Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
Hung-Te Lin9ede2ff2019-08-15 09:43:55 +080016#include <assert.h>
Tristan Shieh4d990ab2019-02-25 17:14:14 +080017#include <bl31.h>
Hung-Te Lin2c307a02019-02-20 14:31:23 +080018#include <boardid.h>
19#include <bootmode.h>
Hung-Te Lin9ede2ff2019-08-15 09:43:55 +080020#include <cbfs.h>
Hung-Te Lin2c307a02019-02-20 14:31:23 +080021#include <console/console.h>
22#include <delay.h>
Tristan Shiehbb684e02018-06-19 16:07:54 +080023#include <device/device.h>
Hung-Te Lin2c307a02019-02-20 14:31:23 +080024#include <edid.h>
25#include <gpio.h>
26#include <soc/ddp.h>
27#include <soc/dsi.h>
Tristan Shieh8db79c12018-09-07 17:26:21 +080028#include <soc/gpio.h>
Tristan Shiehbb684e02018-06-19 16:07:54 +080029#include <soc/mmu_operations.h>
Jiaxin Yu30bc9f42019-04-23 20:45:50 +080030#include <soc/mtcmos.h>
Dawei Chien2422f8c2019-05-30 11:55:10 +080031#include <soc/spm.h>
Tristan Shieh71ae5822018-09-26 14:33:54 +080032#include <soc/usb.h>
Hung-Te Lin9ede2ff2019-08-15 09:43:55 +080033#include <string.h>
Tristan Shiehbb684e02018-06-19 16:07:54 +080034
Tristan Shieh4d990ab2019-02-25 17:14:14 +080035#include "gpio.h"
Hung-Te Lin2c307a02019-02-20 14:31:23 +080036#include "panel.h"
37
Tristan Shieh4d990ab2019-02-25 17:14:14 +080038#include <arm-trusted-firmware/include/export/plat/mediatek/common/plat_params_exp.h>
39
Tristan Shieh8db79c12018-09-07 17:26:21 +080040static void configure_emmc(void)
41{
42 const gpio_t emmc_pin[] = {
43 GPIO(MSDC0_DAT0), GPIO(MSDC0_DAT1),
44 GPIO(MSDC0_DAT2), GPIO(MSDC0_DAT3),
45 GPIO(MSDC0_DAT4), GPIO(MSDC0_DAT5),
46 GPIO(MSDC0_DAT6), GPIO(MSDC0_DAT7),
47 GPIO(MSDC0_CMD), GPIO(MSDC0_RSTB),
48 };
49
50 for (size_t i = 0; i < ARRAY_SIZE(emmc_pin); i++)
51 gpio_set_pull(emmc_pin[i], GPIO_PULL_ENABLE, GPIO_PULL_UP);
52}
53
Tristan Shieh71ae5822018-09-26 14:33:54 +080054static void configure_usb(void)
55{
56 setup_usb_host();
57}
58
Jiaxin Yu30bc9f42019-04-23 20:45:50 +080059static void configure_audio(void)
60{
61 /* Audio PWR*/
62 mtcmos_audio_power_on();
63
64 /* SoC I2S */
65 gpio_set_mode(GPIO(CAM_RST0), PAD_CAM_RST0_FUNC_I2S2_LRCK);
66 gpio_set_mode(GPIO(CAM_PDN1), PAD_CAM_PDN1_FUNC_I2S2_BCK);
67 gpio_set_mode(GPIO(CAM_PDN0), PAD_CAM_PDN0_FUNC_I2S2_MCK);
68 gpio_set_mode(GPIO(EINT3), PAD_EINT3_FUNC_I2S3_DO);
69}
Hung-Te Lin2c307a02019-02-20 14:31:23 +080070
71/* Default implementation for boards without panels defined yet. */
72struct panel_description __weak *get_panel_description(int panel_id)
73{
74 printk(BIOS_ERR, "%s: ERROR: No panels defined for board: %s.\n",
75 __func__, CONFIG_MAINBOARD_PART_NUMBER);
76 return NULL;
77}
78
79/* Set up backlight control pins as output pin and power-off by default */
80static void configure_panel_backlight(void)
81{
82 gpio_output(GPIO(PERIPHERAL_EN13), 0);
83 gpio_output(GPIO(DISP_PWM), 0);
84}
85
86static void power_on_panel(struct panel_description *panel)
87{
88 if (panel->power_on) {
89 panel->power_on();
90 return;
91 }
92
93 /* Default power sequence for most panels. */
94 gpio_output(GPIO_LCM_RST_1V8, 0);
95 gpio_output(GPIO_PPVARP_LCD_EN, 1);
96 gpio_output(GPIO_PPVARN_LCD_EN, 1);
97 gpio_output(GPIO_PP1800_LCM_EN, 1);
98 gpio_output(GPIO_PP3300_LCM_EN, 1);
99 mdelay(6);
100 gpio_output(GPIO_LCM_RST_1V8, 1);
101 mdelay(6);
102}
103
Hung-Te Lin9ede2ff2019-08-15 09:43:55 +0800104struct panel_description *get_panel_from_cbfs(struct panel_description *desc)
105{
106 /* The CBFS name will be panel-{MANUFACTURER}-${PANEL_NAME},
107 * where MANUFACTURER is 3 characters and PANEL_NAME is usually
108 * 13 characters.
109 */
110 char cbfs_name[64];
111 static union {
112 u8 raw[4 * 1024]; /* Most panels only need < 2K. */
113 struct panel_serializable_data s;
114 } buffer;
115
116 if (!desc->name)
117 return NULL;
118
119 snprintf(cbfs_name, sizeof(cbfs_name), "panel-%s", desc->name);
120 if (cbfs_boot_load_file(cbfs_name, buffer.raw, sizeof(buffer),
121 CBFS_TYPE_STRUCT))
122 desc->s = &buffer.s;
123 else
124 printk(BIOS_ERR, "Missing %s in CBFS.\n", cbfs_name);
125
126 return desc->s ? desc : NULL;
127}
128
Hung-Te Lin2c307a02019-02-20 14:31:23 +0800129static struct panel_description *get_active_panel(void)
130{
131 /* TODO(hungte) Create a dedicated panel_id() in board_id.c */
132 int panel_id = sku_id() >> 4;
133
134 struct panel_description *panel = get_panel_description(panel_id);
135 if (!panel) {
136 printk(BIOS_ERR, "%s: Panel %d is not supported.\n",
137 __func__, panel_id);
138 return NULL;
139 }
Hung-Te Lin9ede2ff2019-08-15 09:43:55 +0800140 assert(panel->s);
141
142 const struct edid *edid = &panel->s->edid;
143 const char *name = edid->ascii_string;
Hung-Te Lin2c307a02019-02-20 14:31:23 +0800144 if (name[0] == '\0')
145 name = "unknown name";
Hung-Te Lin9ede2ff2019-08-15 09:43:55 +0800146 printk(BIOS_INFO, "%s: Found ID %d: '%s %s' %dx%d@%dHz\n", __func__,
147 panel_id, edid->manufacturer_name, name, edid->mode.ha,
148 edid->mode.va, edid->mode.refresh);
Hung-Te Lin2c307a02019-02-20 14:31:23 +0800149 return panel;
150}
151
152static bool configure_display(void)
153{
154 struct panel_description *panel = get_active_panel();
155 if (!panel)
156 return false;
157
158 mtcmos_display_power_on();
159 mtcmos_protect_display_bus();
160 configure_panel_backlight();
161 power_on_panel(panel);
162
Hung-Te Lin9ede2ff2019-08-15 09:43:55 +0800163 struct edid *edid = &panel->s->edid;
Hung-Te Lin2c307a02019-02-20 14:31:23 +0800164 edid_set_framebuffer_bits_per_pixel(edid, 32, 0);
165 mtk_ddp_init();
166 u32 mipi_dsi_flags = (MIPI_DSI_MODE_VIDEO |
167 MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
168 MIPI_DSI_MODE_LPM);
169 if (mtk_dsi_init(mipi_dsi_flags, MIPI_DSI_FMT_RGB888, 4, edid,
Hung-Te Lin9ede2ff2019-08-15 09:43:55 +0800170 panel->s->init) < 0) {
Hung-Te Lin2c307a02019-02-20 14:31:23 +0800171 printk(BIOS_ERR, "%s: Failed in DSI init.\n", __func__);
172 return false;
173 }
174 mtk_ddp_mode_set(edid);
175 set_vbe_mode_info_valid(edid, 0);
Hung-Te Lin9ede2ff2019-08-15 09:43:55 +0800176 set_vbe_framebuffer_orientation(panel->s->orientation);
Hung-Te Lin2c307a02019-02-20 14:31:23 +0800177 return true;
178}
179
Tristan Shieh4d990ab2019-02-25 17:14:14 +0800180static void register_reset_to_bl31(void)
181{
182 static struct bl_aux_param_gpio param_reset = {
183 .h = { .type = BL_AUX_PARAM_MTK_RESET_GPIO },
184 .gpio = { .polarity = ARM_TF_GPIO_LEVEL_HIGH },
185 };
186
187 param_reset.gpio.index = GPIO_RESET.id;
188 register_bl31_aux_param(&param_reset.h);
189}
190
Tristan Shiehbb684e02018-06-19 16:07:54 +0800191static void mainboard_init(struct device *dev)
192{
Hung-Te Lin2c307a02019-02-20 14:31:23 +0800193 if (display_init_required()) {
194 printk(BIOS_INFO, "%s: Starting display init.\n", __func__);
195 if (!configure_display())
196 printk(BIOS_ERR, "%s: Failed to init display.\n",
197 __func__);
198 } else {
199 printk(BIOS_INFO, "%s: Skipped display init.\n", __func__);
200 }
201
Tristan Shieh8db79c12018-09-07 17:26:21 +0800202 configure_emmc();
Tristan Shieh71ae5822018-09-26 14:33:54 +0800203 configure_usb();
Jiaxin Yu30bc9f42019-04-23 20:45:50 +0800204 configure_audio();
Dawei Chien2422f8c2019-05-30 11:55:10 +0800205 if (spm_init())
206 printk(BIOS_ERR,
207 "SPM initialization failed, suspend/resume may fail.\n");
Tristan Shieh4d990ab2019-02-25 17:14:14 +0800208
209 register_reset_to_bl31();
Tristan Shiehbb684e02018-06-19 16:07:54 +0800210}
211
212static void mainboard_enable(struct device *dev)
213{
214 dev->ops->init = &mainboard_init;
215}
216
217struct chip_operations mainboard_ops = {
218 .name = CONFIG_MAINBOARD_PART_NUMBER,
219 .enable_dev = mainboard_enable,
220};