From f9bb0baa7596e42d45d556656bbaa3c7d733541b Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Fri, 12 Mar 2021 09:48:25 +0100 Subject: mmc: octeontx_hsmmc: Add support for MIPS Octeon Until now, the Octeontx MMC driver did only support the ARM Octeon TX/Tx2 platforms. This patch adds support for the MIPS Octeon platform to this driver. Here a short summary of the changes: - Enable driver compilation for MIPS Octeon, including the MMC related header file - Reorder header inclusion - Switch to using the clk framework to get the input clock - Remove some functions for MIPS Octeon, as some registers don't exist here Signed-off-by: Stefan Roese Cc: Peng Fan Cc: Aaron Williams Cc: Chandrakala Chavva Cc: Daniel Schwierzeck --- drivers/mmc/octeontx_hsmmc.c | 195 ++++++++++++++++++++++++++++++++----------- 1 file changed, 144 insertions(+), 51 deletions(-) (limited to 'drivers/mmc/octeontx_hsmmc.c') diff --git a/drivers/mmc/octeontx_hsmmc.c b/drivers/mmc/octeontx_hsmmc.c index 442ca493d76..2e569a9e0f6 100644 --- a/drivers/mmc/octeontx_hsmmc.c +++ b/drivers/mmc/octeontx_hsmmc.c @@ -1,13 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2019 Marvell International Ltd. - * - * https://spdx.org/licenses */ -//#define DEBUG +#include #include #include +#include #include #include #include @@ -19,23 +18,31 @@ #include #include #include +#include #include #include - +#include #include #include #include +#if defined(CONFIG_ARCH_OCTEON) +#include +#include +#include +#else #include #include #include -#include -#include - -#include +#endif #include "octeontx_hsmmc.h" +/* Use dummy implementation for MIPS Octeon to always return false */ +#if defined(CONFIG_ARCH_OCTEON) +#define otx_is_soc(ver) 0 +#endif + #define MMC_TIMEOUT_SHORT 20 /* in ms */ #define MMC_TIMEOUT_LONG 1000 #define MMC_TIMEOUT_ERASE 10000 @@ -71,16 +78,18 @@ #define MMC_DEFAULT_TAP_DELAY 4 #define TOTAL_NO_OF_TAPS 512 static void octeontx_mmc_switch_to(struct mmc *mmc); -static int octeontx_mmc_configure_delay(struct mmc *mmc); -static void octeontx_mmc_set_timing(struct mmc *mmc); static void set_wdog(struct mmc *mmc, u64 us); static void do_switch(struct mmc *mmc, union mio_emm_switch emm_switch); static int octeontx_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data); -static int octeontx2_mmc_calc_delay(struct mmc *mmc, int delay); +static int octeontx_mmc_configure_delay(struct mmc *mmc); static int octeontx_mmc_calibrate_delay(struct mmc *mmc); +#if !defined(CONFIG_ARCH_OCTEON) +static int octeontx2_mmc_calc_delay(struct mmc *mmc, int delay); +static void octeontx_mmc_set_timing(struct mmc *mmc); static int octeontx_mmc_set_input_bus_timing(struct mmc *mmc); static int octeontx_mmc_set_output_bus_timing(struct mmc *mmc); +#endif static bool host_probed; @@ -338,6 +347,7 @@ static void mmc_print_status(u32 status) } #endif +#if !defined(CONFIG_ARCH_OCTEON) /** * Print out all of the register values where mmc is optional * @@ -687,6 +697,12 @@ static void octeontx_mmc_print_registers(struct mmc *mmc) if (print) octeontx_mmc_print_registers2(mmc, mmc_to_host(mmc)); } +#else +static void octeontx_mmc_print_registers(struct mmc *mmc) +{ + return; +} +#endif static const struct octeontx_sd_mods octeontx_cr_types[] = { { {0, 0}, {0, 0}, {0, 0} }, /* CMD0 */ @@ -838,14 +854,17 @@ static void octeontx_mmc_track_switch(struct mmc *mmc, u32 cmd_arg) break; case EXT_CSD_HS_TIMING: slot->want_switch.s.hs_timing = 0; +#if !defined(CONFIG_ARCH_OCTEON) slot->want_switch.s.hs200_timing = 0; slot->want_switch.s.hs400_timing = 0; +#endif switch (val & 0xf) { case 0: break; case 1: slot->want_switch.s.hs_timing = 1; break; +#if !defined(CONFIG_ARCH_OCTEON) case 2: if (!slot->is_asim && !slot->is_emul) slot->want_switch.s.hs200_timing = 1; @@ -854,6 +873,7 @@ static void octeontx_mmc_track_switch(struct mmc *mmc, u32 cmd_arg) if (!slot->is_asim && !slot->is_emul) slot->want_switch.s.hs400_timing = 1; break; +#endif default: pr_err("%s(%s): Unsupported timing mode 0x%x\n", __func__, mmc->dev->name, val & 0xf); @@ -2413,7 +2433,10 @@ static u32 octeontx_mmc_calc_clk_period(struct mmc *mmc) struct octeontx_mmc_slot *slot = mmc_to_slot(mmc); struct octeontx_mmc_host *host = slot->host; - return DIV_ROUND_UP(host->sys_freq, mmc->clock); + if (mmc->clock) + return DIV_ROUND_UP(host->sys_freq, mmc->clock); + + return 0; } static int octeontx_mmc_set_ios(struct udevice *dev) @@ -2489,14 +2512,18 @@ static int octeontx_mmc_set_ios(struct udevice *dev) case UHS_SDR25: case UHS_SDR50: case UHS_SDR104: +#if !defined(CONFIG_ARCH_OCTEON) emm_switch.s.hs200_timing = 1; +#endif break; case MMC_HS_400: is_hs400 = true; fallthrough; case UHS_DDR50: case MMC_DDR_52: +#if !defined(CONFIG_ARCH_OCTEON) emm_switch.s.hs400_timing = 1; +#endif break; default: pr_err("%s(%s): Unsupported mode 0x%x\n", __func__, dev->name, @@ -2522,17 +2549,21 @@ static int octeontx_mmc_set_ios(struct udevice *dev) mmc->selected_mode); } +#if !defined(CONFIG_ARCH_OCTEON) debug(" Trying switch 0x%llx w%d hs:%d hs200:%d hs400:%d\n", emm_switch.u, emm_switch.s.bus_width, emm_switch.s.hs_timing, emm_switch.s.hs200_timing, emm_switch.s.hs400_timing); +#endif set_wdog(mmc, 1000); do_switch(mmc, emm_switch); mdelay(100); mode.u = read_csr(mmc, MIO_EMM_MODEX(slot->bus_id)); +#if !defined(CONFIG_ARCH_OCTEON) debug("%s(%s): mode: 0x%llx w:%d, hs:%d, hs200:%d, hs400:%d\n", __func__, dev->name, mode.u, mode.s.bus_width, mode.s.hs_timing, mode.s.hs200_timing, mode.s.hs400_timing); +#endif err = octeontx_mmc_configure_delay(mmc); @@ -2578,6 +2609,26 @@ static int octeontx_mmc_get_wp(struct udevice *dev) return val; } +#if defined(CONFIG_ARCH_OCTEON) +static int octeontx_mmc_configure_delay(struct mmc *mmc) +{ + struct octeontx_mmc_slot *slot = mmc_to_slot(mmc); + union mio_emm_sample emm_sample; + + debug("%s(%s)\n", __func__, mmc->dev->name); + + emm_sample.u = 0; + emm_sample.s.cmd_cnt = slot->cmd_cnt; + emm_sample.s.dat_cnt = slot->dat_cnt; + write_csr(mmc, MIO_EMM_SAMPLE(), emm_sample.u); + + return 0; +} + +static void octeontx_mmc_io_drive_setup(struct mmc *mmc) +{ +} +#else static void octeontx_mmc_set_timing(struct mmc *mmc) { union mio_emm_timing timing; @@ -2613,7 +2664,8 @@ static int octeontx_mmc_configure_delay(struct mmc *mmc) debug("%s(%s)\n", __func__, mmc->dev->name); - if (IS_ENABLED(CONFIG_ARCH_OCTEONTX)) { + if (IS_ENABLED(CONFIG_ARCH_OCTEON) || + IS_ENABLED(CONFIG_ARCH_OCTEONTX)) { union mio_emm_sample emm_sample; emm_sample.u = 0; @@ -2759,6 +2811,28 @@ static int octeontx_mmc_configure_delay(struct mmc *mmc) return 0; } +/** + * Set the IO drive strength and slew + * + * @param mmc mmc device + */ +static void octeontx_mmc_io_drive_setup(struct mmc *mmc) +{ + if (IS_ENABLED(CONFIG_ARCH_OCTEONTX2)) { + struct octeontx_mmc_slot *slot = mmc_to_slot(mmc); + union mio_emm_io_ctl io_ctl; + + if (slot->drive < 0 || slot->slew < 0) + return; + + io_ctl.u = 0; + io_ctl.s.drive = slot->drive; + io_ctl.s.slew = slot->slew; + write_csr(mmc, MIO_EMM_IO_CTL(), io_ctl.u); + } +} +#endif + /** * Sets the MMC watchdog timer in microseconds * @@ -2784,27 +2858,6 @@ static void set_wdog(struct mmc *mmc, u64 us) write_csr(mmc, MIO_EMM_WDOG(), wdog.u); } -/** - * Set the IO drive strength and slew - * - * @param mmc mmc device - */ -static void octeontx_mmc_io_drive_setup(struct mmc *mmc) -{ - if (!IS_ENABLED(CONFIG_ARCH_OCTEONTX)) { - struct octeontx_mmc_slot *slot = mmc_to_slot(mmc); - union mio_emm_io_ctl io_ctl; - - if (slot->drive < 0 || slot->slew < 0) - return; - - io_ctl.u = 0; - io_ctl.s.drive = slot->drive; - io_ctl.s.slew = slot->slew; - write_csr(mmc, MIO_EMM_IO_CTL(), io_ctl.u); - } -} - /** * Print switch errors * @@ -2858,6 +2911,31 @@ static void do_switch(struct mmc *mmc, union mio_emm_switch emm_switch) read_csr(mmc, MIO_EMM_RSP_LO())); } +/** + * Calibrates the delay based on the internal clock + * + * @param mmc Pointer to mmc data structure + * + * @return 0 for success or -ETIMEDOUT on error + * + * NOTE: On error a default value will be calculated. + */ +#if defined(CONFIG_ARCH_OCTEON) +static int octeontx_mmc_set_input_bus_timing(struct mmc *mmc) +{ + return 0; +} + +static int octeontx_mmc_set_output_bus_timing(struct mmc *mmc) +{ + return 0; +} + +static int octeontx_mmc_calibrate_delay(struct mmc *mmc) +{ + return 0; +} +#else /** * Given a delay in ps, return the tap delay count * @@ -2883,15 +2961,6 @@ static int octeontx2_mmc_calc_delay(struct mmc *mmc, int delay) return min_t(int, DIV_ROUND_UP(delay, host->timing_taps), 63); } -/** - * Calibrates the delay based on the internal clock - * - * @param mmc Pointer to mmc data structure - * - * @return 0 for success or -ETIMEDOUT on error - * - * NOTE: On error a default value will be calculated. - */ static int octeontx_mmc_calibrate_delay(struct mmc *mmc) { union mio_emm_calb emm_calb; @@ -3141,6 +3210,7 @@ static int octeontx_mmc_set_output_bus_timing(struct mmc *mmc) return 0; } +#endif static void octeontx_mmc_set_clock(struct mmc *mmc) { @@ -3389,8 +3459,10 @@ static u32 xlate_voltage(u32 voltage) { u32 volt = 0; - /* Convert to millivolts */ - voltage /= 1000; + /* Convert to millivolts. Only necessary on ARM Octeon TX/TX2 */ + if (!IS_ENABLED(CONFIG_ARCH_OCTEON)) + voltage /= 1000; + if (voltage >= 1650 && voltage <= 1950) volt |= MMC_VDD_165_195; if (voltage >= 2000 && voltage <= 2100) @@ -3736,6 +3808,8 @@ static int octeontx_mmc_host_probe(struct udevice *dev) { struct octeontx_mmc_host *host = dev_get_priv(dev); union mio_emm_int emm_int; + struct clk clk; + int ret; u8 rev; debug("%s(%s): Entry host: %p\n", __func__, dev->name, host); @@ -3745,12 +3819,20 @@ static int octeontx_mmc_host_probe(struct udevice *dev) return -ENODEV; } memset(host, 0, sizeof(*host)); - host->base_addr = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, - PCI_REGION_MEM); - if (!host->base_addr) { - pr_err("%s: Error: MMC base address not found\n", __func__); - return -1; + + /* Octeon TX & TX2 use PCI based probing */ + if (device_is_compatible(dev, "cavium,thunder-8890-mmc")) { + host->base_addr = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, + PCI_REGION_MEM); + if (!host->base_addr) { + pr_err("%s: Error: MMC base address not found\n", + __func__); + return -1; + } + } else { + host->base_addr = dev_remap_addr(dev); } + host->dev = dev; debug("%s(%s): Base address: %p\n", __func__, dev->name, host->base_addr); @@ -3760,10 +3842,12 @@ static int octeontx_mmc_host_probe(struct udevice *dev) } host->node = dev_ofnode(dev); host->last_slotid = -1; +#if !defined(CONFIG_ARCH_OCTEON) if (otx_is_platform(PLATFORM_ASIM)) host->is_asim = true; if (otx_is_platform(PLATFORM_EMULATOR)) host->is_emul = true; +#endif host->dma_wait_delay = ofnode_read_u32_default(dev_ofnode(dev), "marvell,dma-wait-delay", 1); @@ -3776,7 +3860,15 @@ static int octeontx_mmc_host_probe(struct udevice *dev) writeq(emm_int.u, host->base_addr + MIO_EMM_INT()); debug("%s(%s): Getting I/O clock\n", __func__, dev->name); - host->sys_freq = octeontx_get_io_clock(); + ret = clk_get_by_index(dev, 0, &clk); + if (ret < 0) + return ret; + + ret = clk_enable(&clk); + if (ret) + return ret; + + host->sys_freq = clk_get_rate(&clk); debug("%s(%s): I/O clock %llu\n", __func__, dev->name, host->sys_freq); if (IS_ENABLED(CONFIG_ARCH_OCTEONTX2)) { @@ -3882,6 +3974,7 @@ static int octeontx_mmc_host_child_pre_probe(struct udevice *dev) static const struct udevice_id octeontx_hsmmc_host_ids[] = { { .compatible = "cavium,thunder-8890-mmc" }, + { .compatible = "cavium,octeon-7360-mmc" }, { } }; -- cgit v1.2.3