/* * (C) Copyright 2012 Teresa Gámez, Phytec Messtechnik GmbH * (C) Copyright 2012-2013 Jan Luebbe * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void __noreturn am33xx_restart_soc(struct restart_handler *rst) { writel(AM33XX_PRM_RSTCTRL_RESET, AM33XX_PRM_RSTCTRL); hang(); } /** * @brief Extract the AM33xx ES revision * * The significance of the CPU revision depends upon the cpu type. * Latest known revision is considered default. * * This function is called before barebox_arm_entry(), so avoid switch * statements. * * @return silicon version */ u32 am33xx_get_cpu_rev(void) { u32 version = (readl(AM33XX_IDCODE_REG) >> 28) & 0xF; if (version == 0) return AM335X_ES1_0; else if (version == 1) return AM335X_ES2_0; else return AM335X_ES2_1; } /** * @brief Get the upper address of current execution * * we can use this to figure out if we are running in SRAM / * XIP Flash or in SDRAM * * @return base address */ static u32 get_base(void) { u32 val; __asm__ __volatile__("mov %0, pc \n":"=r"(val)::"memory"); val &= 0xF0000000; val >>= 28; return val; } /** * @brief Are we running in Flash XIP? * * If the base is in GPMC address space, we probably are! * * @return 1 if we are running in XIP mode, else return 0 */ u32 am33xx_running_in_flash(void) { if (get_base() < 4) return 1; /* in flash */ return 0; /* running in SRAM or SDRAM */ } /** * @brief Are we running in OMAP internal SRAM? * * If in SRAM address, then yes! * * @return 1 if we are running in SRAM, else return 0 */ u32 am33xx_running_in_sram(void) { if (get_base() == 4) return 1; /* in SRAM */ return 0; /* running in FLASH or SDRAM */ } /** * @brief Are we running in SDRAM? * * if we are not in GPMC nor in SRAM address space, * we are in SDRAM execution area * * @return 1 if we are running from SDRAM, else return 0 */ u32 am33xx_running_in_sdram(void) { if (get_base() > 4) return 1; /* in sdram */ return 0; /* running in SRAM or FLASH */ } static int am33xx_bootsource(void) { enum bootsource src; int instance = 0; uint32_t *am33xx_bootinfo = (void *)AM33XX_SRAM_SCRATCH_SPACE; switch (am33xx_bootinfo[2] & 0xFF) { case 0x05: src = BOOTSOURCE_NAND; break; case 0x08: src = BOOTSOURCE_MMC; instance = 0; break; case 0x09: src = BOOTSOURCE_MMC; instance = 1; break; case 0x0b: src = BOOTSOURCE_SPI; break; case 0x41: src = BOOTSOURCE_SERIAL; break; case 0x44: src = BOOTSOURCE_USB; break; case 0x46: src = BOOTSOURCE_NET; break; default: src = BOOTSOURCE_UNKNOWN; } bootsource_set_raw(src, instance); return 0; } static void am33xx_detect_reset_reason(void) { uint32_t val = 0; val = readl(AM33XX_PRM_RSTST); /* clear AM33XX_PRM_RSTST - must be cleared by software * (warm reset insensitive) */ writel(val, AM33XX_PRM_RSTST); switch (val) { case (1 << 9): reset_source_set(RESET_JTAG); break; case (1 << 5): reset_source_set(RESET_EXT); break; case (1 << 4): case (1 << 3): reset_source_set(RESET_WDG); break; case (1 << 1): reset_source_set(RESET_RST); break; case (1 << 0): reset_source_set(RESET_POR); break; default: reset_source_set(RESET_UKWN); break; } } int am33xx_register_ethaddr(int eth_id, int mac_id) { void __iomem *mac_id_low = (void *)AM33XX_MAC_ID0_LO + mac_id * 8; void __iomem *mac_id_high = (void *)AM33XX_MAC_ID0_HI + mac_id * 8; uint8_t mac_addr[6]; uint32_t mac_hi, mac_lo; mac_lo = readl(mac_id_low); mac_hi = readl(mac_id_high); mac_addr[0] = mac_hi & 0xff; mac_addr[1] = (mac_hi & 0xff00) >> 8; mac_addr[2] = (mac_hi & 0xff0000) >> 16; mac_addr[3] = (mac_hi & 0xff000000) >> 24; mac_addr[4] = mac_lo & 0xff; mac_addr[5] = (mac_lo & 0xff00) >> 8; if (is_valid_ether_addr(mac_addr)) { eth_register_ethaddr(eth_id, mac_addr); return 0; } return -ENODEV; } /* GPMC timing for AM33XX nand device */ const struct gpmc_config am33xx_nand_cfg = { .cfg = { 0x00000800, /* CONF1 */ 0x001e1e00, /* CONF2 */ 0x001e1e00, /* CONF3 */ 0x16051807, /* CONF4 */ 0x00151e1e, /* CONF5 */ 0x16000f80, /* CONF6 */ }, .base = 0x08000000, .size = GPMC_SIZE_16M, }; static int am33xx_gpio_init(void) { add_generic_device("omap-gpio", 0, NULL, AM33XX_GPIO0_BASE, 0xf00, IORESOURCE_MEM, NULL); add_generic_device("omap-gpio", 1, NULL, AM33XX_GPIO1_BASE, 0xf00, IORESOURCE_MEM, NULL); add_generic_device("omap-gpio", 2, NULL, AM33XX_GPIO2_BASE, 0xf00, IORESOURCE_MEM, NULL); add_generic_device("omap-gpio", 3, NULL, AM33XX_GPIO3_BASE, 0xf00, IORESOURCE_MEM, NULL); return 0; } int am33xx_init(void) { omap_gpmc_base = (void *)AM33XX_GPMC_BASE; restart_handler_register_fn("soc", am33xx_restart_soc); am33xx_enable_per_clocks(); if (IS_ENABLED(CONFIG_RESET_SOURCE)) am33xx_detect_reset_reason(); return am33xx_bootsource(); } int am33xx_devices_init(void) { am33xx_gpio_init(); add_generic_device("omap-dmtimer", 0, NULL, AM33XX_DMTIMER2_BASE, 0x400, IORESOURCE_MEM, NULL); return 0; } #define VTP_CTRL_READY (0x1 << 5) #define VTP_CTRL_ENABLE (0x1 << 6) #define VTP_CTRL_START_EN (0x1) void am33xx_config_vtp(void) { uint32_t val; val = readl(AM33XX_VTP0_CTRL_REG); val |= VTP_CTRL_ENABLE; writel(val, AM33XX_VTP0_CTRL_REG); val = readl(AM33XX_VTP0_CTRL_REG); val &= ~VTP_CTRL_START_EN; writel(val, AM33XX_VTP0_CTRL_REG); val = readl(AM33XX_VTP0_CTRL_REG); val |= VTP_CTRL_START_EN; writel(val, AM33XX_VTP0_CTRL_REG); /* Poll for READY */ while ((readl(AM33XX_VTP0_CTRL_REG) & VTP_CTRL_READY) != VTP_CTRL_READY) ; } void am33xx_ddr_phydata_cmd_macro(const struct am33xx_cmd_control *cmd_ctrl) { writel(cmd_ctrl->slave_ratio0, AM33XX_CMD0_CTRL_SLAVE_RATIO_0); writel(cmd_ctrl->dll_lock_diff0, AM33XX_CMD0_DLL_LOCK_DIFF_0); writel(cmd_ctrl->invert_clkout0, AM33XX_CMD0_INVERT_CLKOUT_0); writel(cmd_ctrl->slave_ratio1, AM33XX_CMD1_CTRL_SLAVE_RATIO_0); writel(cmd_ctrl->dll_lock_diff1, AM33XX_CMD1_DLL_LOCK_DIFF_0); writel(cmd_ctrl->invert_clkout1, AM33XX_CMD1_INVERT_CLKOUT_0); writel(cmd_ctrl->slave_ratio2, AM33XX_CMD2_CTRL_SLAVE_RATIO_0); writel(cmd_ctrl->dll_lock_diff2, AM33XX_CMD2_DLL_LOCK_DIFF_0); writel(cmd_ctrl->invert_clkout2, AM33XX_CMD2_INVERT_CLKOUT_0); } #define CM_EMIF_SDRAM_CONFIG (AM33XX_CTRL_BASE + 0x110) void am33xx_config_sdram(const struct am33xx_emif_regs *regs) { const void __iomem *emif4 = IOMEM(AM33XX_EMIF4_BASE); writel(regs->emif_read_latency, emif4 + EMIF4_DDR_PHY_CTRL_1); writel(regs->emif_read_latency, emif4 + EMIF4_DDR_PHY_CTRL_1_SHADOW); writel(regs->emif_read_latency, emif4 + EMIF4_DDR_PHY_CTRL_2); writel(regs->emif_tim1, emif4 + EMIF4_SDRAM_TIM_1); writel(regs->emif_tim1, emif4 + EMIF4_SDRAM_TIM_1_SHADOW); writel(regs->emif_tim2, emif4 + EMIF4_SDRAM_TIM_2); writel(regs->emif_tim2, emif4 + EMIF4_SDRAM_TIM_2_SHADOW); writel(regs->emif_tim3, emif4 + EMIF4_SDRAM_TIM_3); writel(regs->emif_tim3, emif4 + EMIF4_SDRAM_TIM_3_SHADOW); if (regs->ocp_config) writel(regs->ocp_config, emif4 + EMIF4_OCP_CONFIG); if (regs->zq_config) { /* * A value of 0x2800 for the REF CTRL will give us * about 570us for a delay, which will be long enough * to configure things. */ writel(0x2800, emif4 + EMIF4_SDRAM_REF_CTRL); writel(regs->zq_config, emif4 + EMIF4_ZQ_CONFIG); writel(regs->sdram_config, CM_EMIF_SDRAM_CONFIG); writel(regs->sdram_config, emif4 + EMIF4_SDRAM_CONFIG); writel(regs->sdram_ref_ctrl, emif4 + EMIF4_SDRAM_REF_CTRL); writel(regs->sdram_ref_ctrl, emif4 + EMIF4_SDRAM_REF_CTRL_SHADOW); } writel(regs->sdram_ref_ctrl, emif4 + EMIF4_SDRAM_REF_CTRL); writel(regs->sdram_ref_ctrl, emif4 + EMIF4_SDRAM_REF_CTRL_SHADOW); writel(regs->sdram_config, emif4 + EMIF4_SDRAM_CONFIG); } void __noreturn am335x_barebox_entry(void *boarddata) { barebox_arm_entry(0x80000000, emif4_sdram_size(IOMEM(AM33XX_EMIF4_BASE)), boarddata); } void am33xx_config_io_ctrl(int ioctrl) { writel(ioctrl, AM33XX_DDR_CMD0_IOCTRL); writel(ioctrl, AM33XX_DDR_CMD1_IOCTRL); writel(ioctrl, AM33XX_DDR_CMD2_IOCTRL); writel(ioctrl, AM33XX_DDR_DATA0_IOCTRL); writel(ioctrl, AM33XX_DDR_DATA1_IOCTRL); } void am33xx_config_ddr_data(const struct am33xx_ddr_data *data, int macronr) { u32 base = 0x0; if (macronr) base = 0xA4; writel(data->rd_slave_ratio0, AM33XX_DATA0_RD_DQS_SLAVE_RATIO_0 + base); writel(data->wr_dqs_slave_ratio0, AM33XX_DATA0_WR_DQS_SLAVE_RATIO_0 + base); writel(data->wrlvl_init_ratio0, AM33XX_DATA0_WRLVL_INIT_RATIO_0 + base); writel(data->gatelvl_init_ratio0, AM33XX_DATA0_GATELVL_INIT_RATIO_0 + base); writel(data->fifo_we_slave_ratio0, AM33XX_DATA0_FIFO_WE_SLAVE_RATIO_0 + base); writel(data->wr_slave_ratio0, AM33XX_DATA0_WR_DATA_SLAVE_RATIO_0 + base); writel(data->use_rank0_delay, AM33XX_DATA0_RANK0_DELAYS_0 + base); writel(data->dll_lock_diff0, AM33XX_DATA0_DLL_LOCK_DIFF_0 + base); } void am335x_sdram_init(int ioctrl, const struct am33xx_cmd_control *cmd_ctrl, const struct am33xx_emif_regs *emif_regs, const struct am33xx_ddr_data *ddr_data) { uint32_t val; am33xx_enable_ddr_clocks(); am33xx_config_vtp(); am33xx_ddr_phydata_cmd_macro(cmd_ctrl); am33xx_config_ddr_data(ddr_data, 0); am33xx_config_ddr_data(ddr_data, 1); am33xx_config_io_ctrl(ioctrl); val = readl(AM33XX_DDR_IO_CTRL); val &= 0xefffffff; writel(val, AM33XX_DDR_IO_CTRL); val = readl(AM33XX_DDR_CKE_CTRL); val |= 0x00000001; writel(val, AM33XX_DDR_CKE_CTRL); am33xx_config_sdram(emif_regs); } #define AM33XX_CONTROL_SMA2_OFS 0x1320 /** * am33xx_select_rmii2_crs_dv - Select RMII2_CRS_DV on GPMC_A9 pin in MODE3 */ void am33xx_select_rmii2_crs_dv(void) { uint32_t val; if (am33xx_get_cpu_rev() == AM335X_ES1_0) return; val = readl(AM33XX_CTRL_BASE + AM33XX_CONTROL_SMA2_OFS); val |= 0x00000001; writel(val, AM33XX_CTRL_BASE + AM33XX_CONTROL_SMA2_OFS); } int am33xx_of_register_bootdevice(void) { struct device *dev; switch (bootsource_get()) { case BOOTSOURCE_MMC: if (bootsource_get_instance() == 0) dev = of_device_enable_and_register_by_alias("mmc0"); else dev = of_device_enable_and_register_by_alias("mmc1"); break; case BOOTSOURCE_NAND: dev = of_device_enable_and_register_by_name("gpmc@50000000"); break; case BOOTSOURCE_SPI: dev = of_device_enable_and_register_by_alias("spi0"); break; case BOOTSOURCE_NET: dev = of_device_enable_and_register_by_alias("ethernet0"); break; default: /* Use nand fallback */ dev = of_device_enable_and_register_by_name("gpmc@50000000"); break; } if (!dev) { printf("Unable to register boot device\n"); return -ENODEV; } return 0; }