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 <sr@denx.de>
Cc: Peng Fan <peng.fan@nxp.com>
Cc: Aaron Williams <awilliams@marvell.com>
Cc: Chandrakala Chavva <cchavva@marvell.com>
Cc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
diff --git a/drivers/mmc/octeontx_hsmmc.c b/drivers/mmc/octeontx_hsmmc.c
index 442ca49..2e569a9 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 <clk.h>
 #include <cpu_func.h>
 #include <dm.h>
+#include <dm/device-internal.h>
 #include <dm/lists.h>
 #include <env.h>
 #include <errno.h>
@@ -19,23 +18,31 @@
 #include <part.h>
 #include <pci.h>
 #include <pci_ids.h>
+#include <power/regulator.h>
 #include <time.h>
 #include <watchdog.h>
-
+#include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/libfdt.h>
 
+#if defined(CONFIG_ARCH_OCTEON)
+#include <mach/octeon-model.h>
+#include <mach/cvmx-regs.h>
+#include <mach/cvmx-mio-emm-defs.h>
+#else
 #include <asm/arch/board.h>
 #include <asm/arch/clock.h>
 #include <asm/arch/csrs/csrs-mio_emm.h>
-#include <asm/io.h>
-#include <dm/device-internal.h>
-
-#include <power/regulator.h>
+#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 @@
 }
 #endif
 
+#if !defined(CONFIG_ARCH_OCTEON)
 /**
  * Print out all of the register values where mmc is optional
  *
@@ -687,6 +697,12 @@
 	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 @@
 		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 @@
 			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 @@
 	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 @@
 	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 @@
 		      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 @@
 	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 @@
 
 	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;
@@ -2760,6 +2812,28 @@
 }
 
 /**
+ * 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
  *
  * @param	mmc	mmc device
@@ -2785,27 +2859,6 @@
 }
 
 /**
- * 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
  *
  * @param	mmc	mmc device
@@ -2858,6 +2911,31 @@
 				 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 @@
 	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 @@
 
 	return 0;
 }
+#endif
 
 static void octeontx_mmc_set_clock(struct mmc *mmc)
 {
@@ -3389,8 +3459,10 @@
 {
 	u32 volt = 0;
 
+	/* Convert to millivolts. Only necessary on ARM Octeon TX/TX2 */
+	if (!IS_ENABLED(CONFIG_ARCH_OCTEON))
+		voltage /= 1000;
+
-	/* Convert to millivolts */
-	voltage /= 1000;
 	if (voltage >= 1650 && voltage <= 1950)
 		volt |= MMC_VDD_165_195;
 	if (voltage >= 2000 && voltage <= 2100)
@@ -3736,6 +3808,8 @@
 {
 	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 @@
 		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 @@
 	}
 	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 @@
 	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 const struct udevice_id octeontx_hsmmc_host_ids[] = {
 	{ .compatible = "cavium,thunder-8890-mmc" },
+	{ .compatible = "cavium,octeon-7360-mmc" },
 	{ }
 };