diff options
Diffstat (limited to 'arch/arm/mach-tegra/board-apalis-tk1-sdhci.c')
-rw-r--r-- | arch/arm/mach-tegra/board-apalis-tk1-sdhci.c | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/board-apalis-tk1-sdhci.c b/arch/arm/mach-tegra/board-apalis-tk1-sdhci.c new file mode 100644 index 000000000000..d45634c4bdf0 --- /dev/null +++ b/arch/arm/mach-tegra/board-apalis-tk1-sdhci.c @@ -0,0 +1,271 @@ +/* + * arch/arm/mach-tegra/board-apalis-tk1-sdhci.c + * + * Copyright (c) 2016, Toradex AG. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/resource.h> +#include <linux/platform_device.h> +#include <linux/wlan_plat.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/mmc/host.h> +#include <linux/wl12xx.h> +#include <linux/platform_data/mmc-sdhci-tegra.h> +#include <linux/mfd/max77660/max77660-core.h> +#include <linux/tegra-fuse.h> +#include <linux/dma-mapping.h> + +#include <asm/mach-types.h> +#include <mach/irqs.h> +#include <mach/gpio-tegra.h> +#include <mach/nct.h> + +#include "gpio-names.h" +#include "board.h" +#include "board-apalis-tk1.h" +#include "dvfs.h" +#include "iomap.h" +#include "tegra-board-id.h" + +#define FUSE_SOC_SPEEDO_0 0x134 + +static struct resource sdhci_resource0[] = { + [0] = { + .start = INT_SDMMC1, + .end = INT_SDMMC1, + .flags = IORESOURCE_IRQ, + }, + [1] = { + .start = TEGRA_SDMMC1_BASE, + .end = TEGRA_SDMMC1_BASE + TEGRA_SDMMC1_SIZE-1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct resource sdhci_resource2[] = { + [0] = { + .start = INT_SDMMC3, + .end = INT_SDMMC3, + .flags = IORESOURCE_IRQ, + }, + [1] = { + .start = TEGRA_SDMMC3_BASE, + .end = TEGRA_SDMMC3_BASE + TEGRA_SDMMC3_SIZE-1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct resource sdhci_resource3[] = { + [0] = { + .start = INT_SDMMC4, + .end = INT_SDMMC4, + .flags = IORESOURCE_IRQ, + }, + [1] = { + .start = TEGRA_SDMMC4_BASE, + .end = TEGRA_SDMMC4_BASE + TEGRA_SDMMC4_SIZE-1, + .flags = IORESOURCE_MEM, + }, +}; + +#ifdef CONFIG_MMC_EMBEDDED_SDIO +static struct embedded_sdio_data embedded_sdio_data0 = { + .cccr = { + .sdio_vsn = 2, + .multi_block = 1, + .low_speed = 0, + .wide_bus = 0, + .high_power = 1, + .high_speed = 1, + }, + .cis = { + .vendor = 0x02d0, + .device = 0x4329, + }, +}; +#endif + +static u64 tegra_sdhci_dmamask = DMA_BIT_MASK(64); + +static struct tegra_sdhci_platform_data tegra_sdhci_platform_data0 = { + .cd_gpio = TEGRA_GPIO_PV3, + .wp_gpio = -1, + .power_gpio = -1, + .tap_delay = 0, + .trim_delay = 0x2, +/* .trim_delay = 0x3, */ +/* TBD + .ddr_clk_limit = 41000000, */ + .uhs_mask = MMC_UHS_MASK_DDR50, + .calib_3v3_offsets = 0x7676, + .calib_1v8_offsets = 0x7676, +/* TBD .max_clk_limit = 136000000, */ +}; + +static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = { + /* + * Don't use SD1_CD# aka SDMMC3_CLK_LB_OUT for now as it features some + * magic properties even though the external loopback is disabled and + * the internal loopback used as per SDMMC_VENDOR_MISC_CNTRL_0 + * register's SDMMC_SPARE1 bits being set to 0xfffd according to the + * TRM! + * .cd_gpio = TEGRA_GPIO_PEE4, + */ + .cd_gpio = -1, + .wp_gpio = -1, + .power_gpio = -1, + .tap_delay = 0, +/* .trim_delay = 0x2, */ + .trim_delay = 0x3, + .uhs_mask = MMC_UHS_MASK_DDR50, + .calib_3v3_offsets = 0x7676, + .calib_1v8_offsets = 0x7676, +}; + +static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = { + .cd_gpio = -1, + .wp_gpio = -1, + .power_gpio = -1, + .is_8bit = 1, + .tap_delay = 0x4, + .trim_delay = 0x4, + .ddr_trim_delay = 0x0, + .mmc_data = { + .built_in = 1, + .ocr_mask = MMC_OCR_1V8_MASK, + }, + .ddr_clk_limit = 51000000, + .max_clk_limit = 200000000, + .calib_3v3_offsets = 0x0202, + .calib_1v8_offsets = 0x0202, +}; + +static struct platform_device tegra_sdhci_device0 = { + .name = "sdhci-tegra", + .id = 0, + .resource = sdhci_resource0, + .num_resources = ARRAY_SIZE(sdhci_resource0), + .dev = { + .dma_mask = &tegra_sdhci_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(64), + .platform_data = &tegra_sdhci_platform_data0, + }, +}; + +static struct platform_device tegra_sdhci_device2 = { + .name = "sdhci-tegra", + .id = 2, + .resource = sdhci_resource2, + .num_resources = ARRAY_SIZE(sdhci_resource2), + .dev = { + .dma_mask = &tegra_sdhci_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(64), + .platform_data = &tegra_sdhci_platform_data2, + }, +}; + +static struct platform_device tegra_sdhci_device3 = { + .name = "sdhci-tegra", + .id = 3, + .resource = sdhci_resource3, + .num_resources = ARRAY_SIZE(sdhci_resource3), + .dev = { + .dma_mask = &tegra_sdhci_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(64), + .platform_data = &tegra_sdhci_platform_data3, + }, +}; + +int __init apalis_tk1_sdhci_init(void) +{ + int nominal_core_mv; + int min_vcore_override_mv; + int boot_vcore_mv; + u32 speedo; + + nominal_core_mv = + tegra_dvfs_rail_get_nominal_millivolts(tegra_core_rail); + if (nominal_core_mv) { + tegra_sdhci_platform_data0.nominal_vcore_mv = nominal_core_mv; + tegra_sdhci_platform_data2.nominal_vcore_mv = nominal_core_mv; + tegra_sdhci_platform_data3.nominal_vcore_mv = nominal_core_mv; + } + min_vcore_override_mv = + tegra_dvfs_rail_get_override_floor(tegra_core_rail); + if (min_vcore_override_mv) { + tegra_sdhci_platform_data0.min_vcore_override_mv = + min_vcore_override_mv; + tegra_sdhci_platform_data2.min_vcore_override_mv = + min_vcore_override_mv; + tegra_sdhci_platform_data3.min_vcore_override_mv = + min_vcore_override_mv; + } + boot_vcore_mv = tegra_dvfs_rail_get_boot_level(tegra_core_rail); + if (boot_vcore_mv) { + tegra_sdhci_platform_data0.boot_vcore_mv = boot_vcore_mv; + tegra_sdhci_platform_data2.boot_vcore_mv = boot_vcore_mv; + tegra_sdhci_platform_data3.boot_vcore_mv = boot_vcore_mv; + } + +/* TBD + tegra_sdhci_platform_data2.max_clk_limit = 204000000; + + tegra_sdhci_platform_data0.default_drv_type = + MMC_SET_DRIVER_TYPE_A; + + tegra_sdhci_platform_data0.max_clk_limit = 204000000; + + tegra_sdhci_platform_data3.uhs_mask = MMC_MASK_HS200; +TBD */ + + /* + * FIXME: Set max clk limit to 200MHz for SDMMC3 for PM375. + * Requesting 208MHz results in getting 204MHz from PLL_P + * and CRC errors are seen with same. + */ + tegra_sdhci_platform_data0.max_clk_limit = 200000000; + tegra_sdhci_platform_data2.max_clk_limit = 200000000; + + speedo = tegra_fuse_readl(FUSE_SOC_SPEEDO_0); + tegra_sdhci_platform_data0.cpu_speedo = speedo; + tegra_sdhci_platform_data2.cpu_speedo = speedo; + tegra_sdhci_platform_data3.cpu_speedo = speedo; + +/* TBD + tegra_sdhci_platform_data0.uhs_mask = + MMC_UHS_MASK_SDR50 | MMC_UHS_MASK_DDR50; + tegra_sdhci_platform_data2.uhs_mask = + MMC_UHS_MASK_SDR50; */ + +/* TBD + tegra_sdhci_platform_data0.max_clk_limit = 204000000; */ + +/* TBD + tegra_sdhci_platform_data2.uhs_mask = + MMC_UHS_MASK_SDR50; + tegra_sdhci_platform_data0.uhs_mask = + MMC_UHS_MASK_SDR50; + tegra_sdhci_platform_data3.max_clk_limit = 200000000; + tegra_sdhci_platform_data2.max_clk_limit = 204000000; */ + + platform_device_register(&tegra_sdhci_device3); + platform_device_register(&tegra_sdhci_device0); + platform_device_register(&tegra_sdhci_device2); + + return 0; +} |