u-boot/board/menlo/m53menlo/m53menlo.c
Marek Vasut 9d371e5fea ARM: imx: mx5: Convert MX53 Menlo board to DM I2C and DM RTC
Convert the board to DM I2C and DM RTC. This leads to removal of board
side iomuxc configuration, which is now done using pin control driver,
and conversion of board side legacy I2C accessors to DM ones.

Signed-off-by: Marek Vasut <marex@denx.de>
Cc: Stefano Babic <sbabic@denx.de>
2022-05-23 11:37:58 +02:00

538 lines
13 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Menlosystems M53Menlo board
*
* Copyright (C) 2012-2017 Marek Vasut <marex@denx.de>
* Copyright (C) 2014-2017 Olaf Mandel <o.mandel@menlosystems.com>
*/
#include <common.h>
#include <dm.h>
#include <init.h>
#include <malloc.h>
#include <asm/global_data.h>
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/sys_proto.h>
#include <asm/arch/crm_regs.h>
#include <asm/arch/clock.h>
#include <asm/arch/iomux-mx53.h>
#include <asm/mach-imx/boot_mode.h>
#include <asm/mach-imx/mx5_video.h>
#include <asm/mach-imx/video.h>
#include <asm/gpio.h>
#include <asm/spl.h>
#include <env.h>
#include <fdt_support.h>
#include <fsl_esdhc_imx.h>
#include <gzip.h>
#include <i2c.h>
#include <ipu_pixfmt.h>
#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/fb.h>
#include <mmc.h>
#include <netdev.h>
#include <spl.h>
#include <splash.h>
#include <usb/ehci-ci.h>
#include <video_console.h>
DECLARE_GLOBAL_DATA_PTR;
static u32 mx53_dram_size[2];
ulong board_get_usable_ram_top(ulong total_size)
{
/*
* WARNING: We must override get_effective_memsize() function here
* to report only the size of the first DRAM bank. This is to make
* U-Boot relocator place U-Boot into valid memory, that is, at the
* end of the first DRAM bank. If we did not override this function
* like so, U-Boot would be placed at the address of the first DRAM
* bank + total DRAM size - sizeof(uboot), which in the setup where
* each DRAM bank contains 512MiB of DRAM would result in placing
* U-Boot into invalid memory area close to the end of the first
* DRAM bank.
*/
return PHYS_SDRAM_2 + mx53_dram_size[1];
}
int dram_init(void)
{
mx53_dram_size[0] = get_ram_size((void *)PHYS_SDRAM_1, 1 << 30);
mx53_dram_size[1] = get_ram_size((void *)PHYS_SDRAM_2, 1 << 30);
gd->ram_size = mx53_dram_size[0] + mx53_dram_size[1];
return 0;
}
int dram_init_banksize(void)
{
gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
gd->bd->bi_dram[0].size = mx53_dram_size[0];
gd->bd->bi_dram[1].start = PHYS_SDRAM_2;
gd->bd->bi_dram[1].size = mx53_dram_size[1];
return 0;
}
static void setup_iomux_uart(void)
{
static const iomux_v3_cfg_t uart_pads[] = {
MX53_PAD_PATA_DMACK__UART1_RXD_MUX,
MX53_PAD_PATA_DIOW__UART1_TXD_MUX,
};
imx_iomux_v3_setup_multiple_pads(uart_pads, ARRAY_SIZE(uart_pads));
}
static void setup_iomux_fec(void)
{
static const iomux_v3_cfg_t fec_pads[] = {
/* MDIO pads */
NEW_PAD_CTRL(MX53_PAD_FEC_MDIO__FEC_MDIO, PAD_CTL_HYS |
PAD_CTL_DSE_HIGH | PAD_CTL_PUS_22K_UP | PAD_CTL_ODE),
NEW_PAD_CTRL(MX53_PAD_FEC_MDC__FEC_MDC, PAD_CTL_DSE_HIGH),
/* FEC 0 pads */
NEW_PAD_CTRL(MX53_PAD_FEC_CRS_DV__FEC_RX_DV,
PAD_CTL_HYS | PAD_CTL_PKE),
NEW_PAD_CTRL(MX53_PAD_FEC_REF_CLK__FEC_TX_CLK,
PAD_CTL_HYS | PAD_CTL_PKE),
NEW_PAD_CTRL(MX53_PAD_FEC_RX_ER__FEC_RX_ER,
PAD_CTL_HYS | PAD_CTL_PKE),
NEW_PAD_CTRL(MX53_PAD_FEC_TX_EN__FEC_TX_EN, PAD_CTL_DSE_HIGH),
NEW_PAD_CTRL(MX53_PAD_FEC_RXD0__FEC_RDATA_0,
PAD_CTL_HYS | PAD_CTL_PKE),
NEW_PAD_CTRL(MX53_PAD_FEC_RXD1__FEC_RDATA_1,
PAD_CTL_HYS | PAD_CTL_PKE),
NEW_PAD_CTRL(MX53_PAD_FEC_TXD0__FEC_TDATA_0, PAD_CTL_DSE_HIGH),
NEW_PAD_CTRL(MX53_PAD_FEC_TXD1__FEC_TDATA_1, PAD_CTL_DSE_HIGH),
/* FEC 1 pads */
NEW_PAD_CTRL(MX53_PAD_KEY_COL0__FEC_RDATA_3,
PAD_CTL_HYS | PAD_CTL_PKE),
NEW_PAD_CTRL(MX53_PAD_KEY_ROW0__FEC_TX_ER,
PAD_CTL_HYS | PAD_CTL_PKE),
NEW_PAD_CTRL(MX53_PAD_KEY_COL1__FEC_RX_CLK,
PAD_CTL_HYS | PAD_CTL_PKE),
NEW_PAD_CTRL(MX53_PAD_KEY_ROW1__FEC_COL,
PAD_CTL_HYS | PAD_CTL_PKE),
NEW_PAD_CTRL(MX53_PAD_KEY_COL2__FEC_RDATA_2,
PAD_CTL_HYS | PAD_CTL_PKE),
NEW_PAD_CTRL(MX53_PAD_KEY_ROW2__FEC_TDATA_2, PAD_CTL_DSE_HIGH),
NEW_PAD_CTRL(MX53_PAD_KEY_COL3__FEC_CRS,
PAD_CTL_HYS | PAD_CTL_PKE),
NEW_PAD_CTRL(MX53_PAD_GPIO_19__FEC_TDATA_3, PAD_CTL_DSE_HIGH),
};
imx_iomux_v3_setup_multiple_pads(fec_pads, ARRAY_SIZE(fec_pads));
}
#ifdef CONFIG_FSL_ESDHC_IMX
struct fsl_esdhc_cfg esdhc_cfg = {
MMC_SDHC1_BASE_ADDR,
};
int board_mmc_getcd(struct mmc *mmc)
{
imx_iomux_v3_setup_pad(MX53_PAD_GPIO_1__GPIO1_1);
gpio_direction_input(IMX_GPIO_NR(1, 1));
return !gpio_get_value(IMX_GPIO_NR(1, 1));
}
#define SD_CMD_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_DSE_HIGH | \
PAD_CTL_PUS_100K_UP)
#define SD_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_PUS_47K_UP | \
PAD_CTL_DSE_HIGH)
int board_mmc_init(struct bd_info *bis)
{
static const iomux_v3_cfg_t sd1_pads[] = {
NEW_PAD_CTRL(MX53_PAD_SD1_CMD__ESDHC1_CMD, SD_CMD_PAD_CTRL),
NEW_PAD_CTRL(MX53_PAD_SD1_CLK__ESDHC1_CLK, SD_PAD_CTRL),
NEW_PAD_CTRL(MX53_PAD_SD1_DATA0__ESDHC1_DAT0, SD_PAD_CTRL),
NEW_PAD_CTRL(MX53_PAD_SD1_DATA1__ESDHC1_DAT1, SD_PAD_CTRL),
NEW_PAD_CTRL(MX53_PAD_SD1_DATA2__ESDHC1_DAT2, SD_PAD_CTRL),
NEW_PAD_CTRL(MX53_PAD_SD1_DATA3__ESDHC1_DAT3, SD_PAD_CTRL),
};
esdhc_cfg.sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK);
imx_iomux_v3_setup_multiple_pads(sd1_pads, ARRAY_SIZE(sd1_pads));
return fsl_esdhc_initialize(bis, &esdhc_cfg);
}
#endif
static void enable_lvds_clock(struct display_info_t const *dev, const u8 hclk)
{
static struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)MXC_CCM_BASE;
int ret;
/* For ETM0430G0DH6 model, this must be enabled before the clock. */
gpio_direction_output(IMX_GPIO_NR(6, 0), 1);
/*
* Set LVDS clock to 33.28 MHz for the display. The PLL4 is set to
* 233 MHz, divided by 7 by setting CCM_CSCMR2 LDB_DI0_IPU_DIV=1 .
*/
ret = mxc_set_clock(MXC_HCLK, hclk, MXC_LDB_CLK);
if (ret)
puts("IPU: Failed to configure LDB clock\n");
/* Configure CCM_CSCMR2 */
clrsetbits_le32(&mxc_ccm->cscmr2,
(0x7 << 26) | BIT(10) | BIT(8),
(0x5 << 26) | BIT(10) | BIT(8));
/* Configure LDB_CTRL */
writel(0x201, 0x53fa8008);
}
static void enable_lvds_etm0430g0dh6(struct display_info_t const *dev)
{
gpio_request(IMX_GPIO_NR(6, 0), "LCD");
/* For ETM0430G0DH6 model, this must be enabled before the clock. */
gpio_direction_output(IMX_GPIO_NR(6, 0), 1);
/*
* Set LVDS clock to 9 MHz for the display. The PLL4 is set to
* 63 MHz, divided by 7 by setting CCM_CSCMR2 LDB_DI0_IPU_DIV=1 .
*/
enable_lvds_clock(dev, 63);
}
static void enable_lvds_etm0700g0dh6(struct display_info_t const *dev)
{
gpio_request(IMX_GPIO_NR(6, 0), "LCD");
/*
* Set LVDS clock to 33.28 MHz for the display. The PLL4 is set to
* 233 MHz, divided by 7 by setting CCM_CSCMR2 LDB_DI0_IPU_DIV=1 .
*/
enable_lvds_clock(dev, 233);
/* For ETM0700G0DH6 model, this may be enabled after the clock. */
gpio_direction_output(IMX_GPIO_NR(6, 0), 1);
}
static const char *lvds_compat_string;
static int detect_lvds(struct display_info_t const *dev)
{
struct udevice *idev, *ibus;
u8 touchid[23];
u8 *touchptr = &touchid[0];
int ret;
ret = uclass_get_device_by_seq(UCLASS_I2C, 0, &ibus);
if (ret)
return 0;
ret = dm_i2c_probe(ibus, 0x38, 0, &idev);
if (ret)
return 0;
/* Touchscreen is at address 0x38, ID register is 0xbb. */
ret = dm_i2c_read(idev, 0xbb, touchid, sizeof(touchid));
if (ret)
return 0;
/* EP0430 prefixes the response with 0xbb, skip it. */
if (*touchptr == 0xbb)
touchptr++;
/* Skip the 'EP' prefix. */
touchptr += 2;
ret = !memcmp(touchptr, &dev->mode.name[7], 4);
if (ret)
lvds_compat_string = dev->mode.name;
return ret;
}
void board_preboot_os(void)
{
/* Power off the LCD to prevent awful color flicker */
gpio_direction_output(IMX_GPIO_NR(6, 0), 0);
}
int ft_board_setup(void *blob, struct bd_info *bd)
{
if (lvds_compat_string)
do_fixup_by_path_string(blob, "/panel", "compatible",
lvds_compat_string);
return 0;
}
struct display_info_t const displays[] = {
{
.bus = 0,
.addr = 0,
.detect = detect_lvds,
.enable = enable_lvds_etm0430g0dh6,
.pixfmt = IPU_PIX_FMT_RGB666,
.mode = {
.name = "edt,etm0430g0dh6",
.refresh = 60,
.xres = 480,
.yres = 272,
.pixclock = 111111, /* picosecond (9 MHz) */
.left_margin = 2,
.right_margin = 2,
.upper_margin = 2,
.lower_margin = 2,
.hsync_len = 41,
.vsync_len = 10,
.sync = 0x40000000,
.vmode = FB_VMODE_NONINTERLACED
}
}, {
.bus = 0,
.addr = 0,
.detect = detect_lvds,
.enable = enable_lvds_etm0700g0dh6,
.pixfmt = IPU_PIX_FMT_RGB666,
.mode = {
.name = "edt,etm0700g0dh6",
.refresh = 60,
.xres = 800,
.yres = 480,
.pixclock = 30048, /* picosecond (33.28 MHz) */
.left_margin = 40,
.right_margin = 88,
.upper_margin = 10,
.lower_margin = 33,
.hsync_len = 128,
.vsync_len = 2,
.sync = FB_SYNC_EXT,
.vmode = FB_VMODE_NONINTERLACED
}
}
};
size_t display_count = ARRAY_SIZE(displays);
#ifdef CONFIG_SPLASH_SCREEN
static struct splash_location default_splash_locations[] = {
{
.name = "mmc_fs",
.storage = SPLASH_STORAGE_MMC,
.flags = SPLASH_STORAGE_FS,
.devpart = "0:1",
},
};
int splash_screen_prepare(void)
{
return splash_source_load(default_splash_locations,
ARRAY_SIZE(default_splash_locations));
}
#endif
int board_late_init(void)
{
#ifdef CONFIG_CMD_BMODE
add_board_boot_modes(NULL);
#endif
#if defined(CONFIG_VIDEO_IPUV3)
struct udevice *dev;
int xpos, ypos, ret;
char *s;
void *dst;
ulong addr, len;
splash_get_pos(&xpos, &ypos);
s = env_get("splashimage");
if (!s)
return 0;
addr = hextoul(s, NULL);
dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE);
if (!dst)
return -ENOMEM;
ret = splash_screen_prepare();
if (ret < 0)
goto splasherr;
len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE;
ret = gunzip(dst + 2, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE - 2,
(uchar *)addr, &len);
if (ret) {
printf("Error: no valid bmp or bmp.gz image at %lx\n", addr);
goto splasherr;
}
ret = uclass_get_device(UCLASS_VIDEO, 0, &dev);
if (ret)
goto splasherr;
ret = video_bmp_display(dev, (ulong)dst + 2, xpos, ypos, true);
if (ret)
goto splasherr;
return 0;
splasherr:
free(dst);
#endif
return 0;
}
static void setup_iomux_video(void)
{
static const iomux_v3_cfg_t lcd_pads[] = {
MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3,
MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK,
MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2,
MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1,
MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0,
};
imx_iomux_v3_setup_multiple_pads(lcd_pads, ARRAY_SIZE(lcd_pads));
}
static void setup_iomux_nand(void)
{
static const iomux_v3_cfg_t nand_pads[] = {
NEW_PAD_CTRL(MX53_PAD_NANDF_WE_B__EMI_NANDF_WE_B,
PAD_CTL_DSE_HIGH),
NEW_PAD_CTRL(MX53_PAD_NANDF_RE_B__EMI_NANDF_RE_B,
PAD_CTL_DSE_HIGH),
NEW_PAD_CTRL(MX53_PAD_NANDF_CLE__EMI_NANDF_CLE,
PAD_CTL_DSE_HIGH),
NEW_PAD_CTRL(MX53_PAD_NANDF_ALE__EMI_NANDF_ALE,
PAD_CTL_DSE_HIGH),
NEW_PAD_CTRL(MX53_PAD_NANDF_WP_B__EMI_NANDF_WP_B,
PAD_CTL_PUS_100K_UP),
NEW_PAD_CTRL(MX53_PAD_NANDF_RB0__EMI_NANDF_RB_0,
PAD_CTL_PUS_100K_UP),
NEW_PAD_CTRL(MX53_PAD_NANDF_CS0__EMI_NANDF_CS_0,
PAD_CTL_DSE_HIGH),
NEW_PAD_CTRL(MX53_PAD_PATA_DATA0__EMI_NANDF_D_0,
PAD_CTL_DSE_HIGH | PAD_CTL_PKE),
NEW_PAD_CTRL(MX53_PAD_PATA_DATA1__EMI_NANDF_D_1,
PAD_CTL_DSE_HIGH | PAD_CTL_PKE),
NEW_PAD_CTRL(MX53_PAD_PATA_DATA2__EMI_NANDF_D_2,
PAD_CTL_DSE_HIGH | PAD_CTL_PKE),
NEW_PAD_CTRL(MX53_PAD_PATA_DATA3__EMI_NANDF_D_3,
PAD_CTL_DSE_HIGH | PAD_CTL_PKE),
NEW_PAD_CTRL(MX53_PAD_PATA_DATA4__EMI_NANDF_D_4,
PAD_CTL_DSE_HIGH | PAD_CTL_PKE),
NEW_PAD_CTRL(MX53_PAD_PATA_DATA5__EMI_NANDF_D_5,
PAD_CTL_DSE_HIGH | PAD_CTL_PKE),
NEW_PAD_CTRL(MX53_PAD_PATA_DATA6__EMI_NANDF_D_6,
PAD_CTL_DSE_HIGH | PAD_CTL_PKE),
NEW_PAD_CTRL(MX53_PAD_PATA_DATA7__EMI_NANDF_D_7,
PAD_CTL_DSE_HIGH | PAD_CTL_PKE),
};
imx_iomux_v3_setup_multiple_pads(nand_pads, ARRAY_SIZE(nand_pads));
}
static void m53_set_clock(void)
{
int ret;
const u32 ref_clk = MXC_HCLK;
const u32 dramclk = 400;
u32 cpuclk;
gpio_request(IMX_GPIO_NR(4, 0), "CPUCLK");
imx_iomux_v3_setup_pad(NEW_PAD_CTRL(MX53_PAD_GPIO_10__GPIO4_0,
PAD_CTL_DSE_HIGH | PAD_CTL_PKE));
gpio_direction_input(IMX_GPIO_NR(4, 0));
/* GPIO10 selects modules' CPU speed, 1 = 1200MHz ; 0 = 800MHz */
cpuclk = gpio_get_value(IMX_GPIO_NR(4, 0)) ? 1200 : 800;
ret = mxc_set_clock(ref_clk, cpuclk, MXC_ARM_CLK);
if (ret)
printf("CPU: Switch CPU clock to %dMHz failed\n", cpuclk);
ret = mxc_set_clock(ref_clk, dramclk, MXC_PERIPH_CLK);
if (ret) {
printf("CPU: Switch peripheral clock to %dMHz failed\n",
dramclk);
}
ret = mxc_set_clock(ref_clk, dramclk, MXC_DDR_CLK);
if (ret)
printf("CPU: Switch DDR clock to %dMHz failed\n", dramclk);
}
static void m53_set_nand(void)
{
u32 i;
/* NAND flash is muxed on ATA pins */
setbits_le32(M4IF_BASE_ADDR + 0xc, M4IF_GENP_WEIM_MM_MASK);
/* Wait for Grant/Ack sequence (see EIM_CSnGCR2:MUX16_BYP_GRANT) */
for (i = 0x4; i < 0x94; i += 0x18) {
clrbits_le32(WEIM_BASE_ADDR + i,
WEIM_GCR2_MUX16_BYP_GRANT_MASK);
}
mxc_set_clock(0, 33, MXC_NFC_CLK);
enable_nfc_clk(1);
}
int board_early_init_f(void)
{
setup_iomux_uart();
setup_iomux_fec();
setup_iomux_nand();
setup_iomux_video();
m53_set_clock();
mxc_set_sata_internal_clock();
/* NAND clock @ 33MHz */
m53_set_nand();
return 0;
}
int board_init(void)
{
gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100;
return 0;
}
int checkboard(void)
{
puts("Board: Menlosystems M53Menlo\n");
return 0;
}
/*
* NAND SPL
*/
#ifdef CONFIG_SPL_BUILD
void spl_board_init(void)
{
setup_iomux_nand();
m53_set_clock();
m53_set_nand();
}
u32 spl_boot_device(void)
{
return BOOT_DEVICE_NAND;
}
#endif