18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2011-2016 Zhang, Keguang <keguang.zhang@gmail.com>
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/clk.h>
78c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
88c2ecf20Sopenharmony_ci#include <linux/err.h>
98c2ecf20Sopenharmony_ci#include <linux/mtd/partitions.h>
108c2ecf20Sopenharmony_ci#include <linux/sizes.h>
118c2ecf20Sopenharmony_ci#include <linux/phy.h>
128c2ecf20Sopenharmony_ci#include <linux/serial_8250.h>
138c2ecf20Sopenharmony_ci#include <linux/stmmac.h>
148c2ecf20Sopenharmony_ci#include <linux/usb/ehci_pdriver.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <platform.h>
178c2ecf20Sopenharmony_ci#include <loongson1.h>
188c2ecf20Sopenharmony_ci#include <cpufreq.h>
198c2ecf20Sopenharmony_ci#include <dma.h>
208c2ecf20Sopenharmony_ci#include <nand.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/* 8250/16550 compatible UART */
238c2ecf20Sopenharmony_ci#define LS1X_UART(_id)						\
248c2ecf20Sopenharmony_ci	{							\
258c2ecf20Sopenharmony_ci		.mapbase	= LS1X_UART ## _id ## _BASE,	\
268c2ecf20Sopenharmony_ci		.irq		= LS1X_UART ## _id ## _IRQ,	\
278c2ecf20Sopenharmony_ci		.iotype		= UPIO_MEM,			\
288c2ecf20Sopenharmony_ci		.flags		= UPF_IOREMAP | UPF_FIXED_TYPE, \
298c2ecf20Sopenharmony_ci		.type		= PORT_16550A,			\
308c2ecf20Sopenharmony_ci	}
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic struct plat_serial8250_port ls1x_serial8250_pdata[] = {
338c2ecf20Sopenharmony_ci	LS1X_UART(0),
348c2ecf20Sopenharmony_ci	LS1X_UART(1),
358c2ecf20Sopenharmony_ci	LS1X_UART(2),
368c2ecf20Sopenharmony_ci	LS1X_UART(3),
378c2ecf20Sopenharmony_ci	{},
388c2ecf20Sopenharmony_ci};
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistruct platform_device ls1x_uart_pdev = {
418c2ecf20Sopenharmony_ci	.name		= "serial8250",
428c2ecf20Sopenharmony_ci	.id		= PLAT8250_DEV_PLATFORM,
438c2ecf20Sopenharmony_ci	.dev		= {
448c2ecf20Sopenharmony_ci		.platform_data = ls1x_serial8250_pdata,
458c2ecf20Sopenharmony_ci	},
468c2ecf20Sopenharmony_ci};
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_civoid __init ls1x_serial_set_uartclk(struct platform_device *pdev)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	struct clk *clk;
518c2ecf20Sopenharmony_ci	struct plat_serial8250_port *p;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	clk = clk_get(&pdev->dev, pdev->name);
548c2ecf20Sopenharmony_ci	if (IS_ERR(clk)) {
558c2ecf20Sopenharmony_ci		pr_err("unable to get %s clock, err=%ld",
568c2ecf20Sopenharmony_ci		       pdev->name, PTR_ERR(clk));
578c2ecf20Sopenharmony_ci		return;
588c2ecf20Sopenharmony_ci	}
598c2ecf20Sopenharmony_ci	clk_prepare_enable(clk);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	for (p = pdev->dev.platform_data; p->flags != 0; ++p)
628c2ecf20Sopenharmony_ci		p->uartclk = clk_get_rate(clk);
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci/* CPUFreq */
668c2ecf20Sopenharmony_cistatic struct plat_ls1x_cpufreq ls1x_cpufreq_pdata = {
678c2ecf20Sopenharmony_ci	.clk_name	= "cpu_clk",
688c2ecf20Sopenharmony_ci	.osc_clk_name	= "osc_clk",
698c2ecf20Sopenharmony_ci	.max_freq	= 266 * 1000,
708c2ecf20Sopenharmony_ci	.min_freq	= 33 * 1000,
718c2ecf20Sopenharmony_ci};
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistruct platform_device ls1x_cpufreq_pdev = {
748c2ecf20Sopenharmony_ci	.name		= "ls1x-cpufreq",
758c2ecf20Sopenharmony_ci	.dev		= {
768c2ecf20Sopenharmony_ci		.platform_data = &ls1x_cpufreq_pdata,
778c2ecf20Sopenharmony_ci	},
788c2ecf20Sopenharmony_ci};
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci/* Synopsys Ethernet GMAC */
818c2ecf20Sopenharmony_cistatic struct stmmac_mdio_bus_data ls1x_mdio_bus_data = {
828c2ecf20Sopenharmony_ci	.phy_mask	= 0,
838c2ecf20Sopenharmony_ci};
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic struct stmmac_dma_cfg ls1x_eth_dma_cfg = {
868c2ecf20Sopenharmony_ci	.pbl		= 1,
878c2ecf20Sopenharmony_ci};
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ciint ls1x_eth_mux_init(struct platform_device *pdev, void *priv)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	struct plat_stmmacenet_data *plat_dat = NULL;
928c2ecf20Sopenharmony_ci	u32 val;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	val = __raw_readl(LS1X_MUX_CTRL1);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci#if defined(CONFIG_LOONGSON1_LS1B)
978c2ecf20Sopenharmony_ci	plat_dat = dev_get_platdata(&pdev->dev);
988c2ecf20Sopenharmony_ci	if (plat_dat->bus_id) {
998c2ecf20Sopenharmony_ci		__raw_writel(__raw_readl(LS1X_MUX_CTRL0) | GMAC1_USE_UART1 |
1008c2ecf20Sopenharmony_ci			     GMAC1_USE_UART0, LS1X_MUX_CTRL0);
1018c2ecf20Sopenharmony_ci		switch (plat_dat->phy_interface) {
1028c2ecf20Sopenharmony_ci		case PHY_INTERFACE_MODE_RGMII:
1038c2ecf20Sopenharmony_ci			val &= ~(GMAC1_USE_TXCLK | GMAC1_USE_PWM23);
1048c2ecf20Sopenharmony_ci			break;
1058c2ecf20Sopenharmony_ci		case PHY_INTERFACE_MODE_MII:
1068c2ecf20Sopenharmony_ci			val |= (GMAC1_USE_TXCLK | GMAC1_USE_PWM23);
1078c2ecf20Sopenharmony_ci			break;
1088c2ecf20Sopenharmony_ci		default:
1098c2ecf20Sopenharmony_ci			pr_err("unsupported mii mode %d\n",
1108c2ecf20Sopenharmony_ci			       plat_dat->phy_interface);
1118c2ecf20Sopenharmony_ci			return -ENOTSUPP;
1128c2ecf20Sopenharmony_ci		}
1138c2ecf20Sopenharmony_ci		val &= ~GMAC1_SHUT;
1148c2ecf20Sopenharmony_ci	} else {
1158c2ecf20Sopenharmony_ci		switch (plat_dat->phy_interface) {
1168c2ecf20Sopenharmony_ci		case PHY_INTERFACE_MODE_RGMII:
1178c2ecf20Sopenharmony_ci			val &= ~(GMAC0_USE_TXCLK | GMAC0_USE_PWM01);
1188c2ecf20Sopenharmony_ci			break;
1198c2ecf20Sopenharmony_ci		case PHY_INTERFACE_MODE_MII:
1208c2ecf20Sopenharmony_ci			val |= (GMAC0_USE_TXCLK | GMAC0_USE_PWM01);
1218c2ecf20Sopenharmony_ci			break;
1228c2ecf20Sopenharmony_ci		default:
1238c2ecf20Sopenharmony_ci			pr_err("unsupported mii mode %d\n",
1248c2ecf20Sopenharmony_ci			       plat_dat->phy_interface);
1258c2ecf20Sopenharmony_ci			return -ENOTSUPP;
1268c2ecf20Sopenharmony_ci		}
1278c2ecf20Sopenharmony_ci		val &= ~GMAC0_SHUT;
1288c2ecf20Sopenharmony_ci	}
1298c2ecf20Sopenharmony_ci	__raw_writel(val, LS1X_MUX_CTRL1);
1308c2ecf20Sopenharmony_ci#elif defined(CONFIG_LOONGSON1_LS1C)
1318c2ecf20Sopenharmony_ci	plat_dat = dev_get_platdata(&pdev->dev);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	val &= ~PHY_INTF_SELI;
1348c2ecf20Sopenharmony_ci	if (plat_dat->phy_interface == PHY_INTERFACE_MODE_RMII)
1358c2ecf20Sopenharmony_ci		val |= 0x4 << PHY_INTF_SELI_SHIFT;
1368c2ecf20Sopenharmony_ci	__raw_writel(val, LS1X_MUX_CTRL1);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	val = __raw_readl(LS1X_MUX_CTRL0);
1398c2ecf20Sopenharmony_ci	__raw_writel(val & (~GMAC_SHUT), LS1X_MUX_CTRL0);
1408c2ecf20Sopenharmony_ci#endif
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	return 0;
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic struct plat_stmmacenet_data ls1x_eth0_pdata = {
1468c2ecf20Sopenharmony_ci	.bus_id			= 0,
1478c2ecf20Sopenharmony_ci	.phy_addr		= -1,
1488c2ecf20Sopenharmony_ci#if defined(CONFIG_LOONGSON1_LS1B)
1498c2ecf20Sopenharmony_ci	.phy_interface		= PHY_INTERFACE_MODE_MII,
1508c2ecf20Sopenharmony_ci#elif defined(CONFIG_LOONGSON1_LS1C)
1518c2ecf20Sopenharmony_ci	.phy_interface		= PHY_INTERFACE_MODE_RMII,
1528c2ecf20Sopenharmony_ci#endif
1538c2ecf20Sopenharmony_ci	.mdio_bus_data		= &ls1x_mdio_bus_data,
1548c2ecf20Sopenharmony_ci	.dma_cfg		= &ls1x_eth_dma_cfg,
1558c2ecf20Sopenharmony_ci	.has_gmac		= 1,
1568c2ecf20Sopenharmony_ci	.tx_coe			= 1,
1578c2ecf20Sopenharmony_ci	.rx_queues_to_use	= 1,
1588c2ecf20Sopenharmony_ci	.tx_queues_to_use	= 1,
1598c2ecf20Sopenharmony_ci	.init			= ls1x_eth_mux_init,
1608c2ecf20Sopenharmony_ci};
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic struct resource ls1x_eth0_resources[] = {
1638c2ecf20Sopenharmony_ci	[0] = {
1648c2ecf20Sopenharmony_ci		.start	= LS1X_GMAC0_BASE,
1658c2ecf20Sopenharmony_ci		.end	= LS1X_GMAC0_BASE + SZ_64K - 1,
1668c2ecf20Sopenharmony_ci		.flags	= IORESOURCE_MEM,
1678c2ecf20Sopenharmony_ci	},
1688c2ecf20Sopenharmony_ci	[1] = {
1698c2ecf20Sopenharmony_ci		.name	= "macirq",
1708c2ecf20Sopenharmony_ci		.start	= LS1X_GMAC0_IRQ,
1718c2ecf20Sopenharmony_ci		.flags	= IORESOURCE_IRQ,
1728c2ecf20Sopenharmony_ci	},
1738c2ecf20Sopenharmony_ci};
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistruct platform_device ls1x_eth0_pdev = {
1768c2ecf20Sopenharmony_ci	.name		= "stmmaceth",
1778c2ecf20Sopenharmony_ci	.id		= 0,
1788c2ecf20Sopenharmony_ci	.num_resources	= ARRAY_SIZE(ls1x_eth0_resources),
1798c2ecf20Sopenharmony_ci	.resource	= ls1x_eth0_resources,
1808c2ecf20Sopenharmony_ci	.dev		= {
1818c2ecf20Sopenharmony_ci		.platform_data = &ls1x_eth0_pdata,
1828c2ecf20Sopenharmony_ci	},
1838c2ecf20Sopenharmony_ci};
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci#ifdef CONFIG_LOONGSON1_LS1B
1868c2ecf20Sopenharmony_cistatic struct plat_stmmacenet_data ls1x_eth1_pdata = {
1878c2ecf20Sopenharmony_ci	.bus_id			= 1,
1888c2ecf20Sopenharmony_ci	.phy_addr		= -1,
1898c2ecf20Sopenharmony_ci	.phy_interface		= PHY_INTERFACE_MODE_MII,
1908c2ecf20Sopenharmony_ci	.mdio_bus_data		= &ls1x_mdio_bus_data,
1918c2ecf20Sopenharmony_ci	.dma_cfg		= &ls1x_eth_dma_cfg,
1928c2ecf20Sopenharmony_ci	.has_gmac		= 1,
1938c2ecf20Sopenharmony_ci	.tx_coe			= 1,
1948c2ecf20Sopenharmony_ci	.rx_queues_to_use	= 1,
1958c2ecf20Sopenharmony_ci	.tx_queues_to_use	= 1,
1968c2ecf20Sopenharmony_ci	.init			= ls1x_eth_mux_init,
1978c2ecf20Sopenharmony_ci};
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic struct resource ls1x_eth1_resources[] = {
2008c2ecf20Sopenharmony_ci	[0] = {
2018c2ecf20Sopenharmony_ci		.start	= LS1X_GMAC1_BASE,
2028c2ecf20Sopenharmony_ci		.end	= LS1X_GMAC1_BASE + SZ_64K - 1,
2038c2ecf20Sopenharmony_ci		.flags	= IORESOURCE_MEM,
2048c2ecf20Sopenharmony_ci	},
2058c2ecf20Sopenharmony_ci	[1] = {
2068c2ecf20Sopenharmony_ci		.name	= "macirq",
2078c2ecf20Sopenharmony_ci		.start	= LS1X_GMAC1_IRQ,
2088c2ecf20Sopenharmony_ci		.flags	= IORESOURCE_IRQ,
2098c2ecf20Sopenharmony_ci	},
2108c2ecf20Sopenharmony_ci};
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistruct platform_device ls1x_eth1_pdev = {
2138c2ecf20Sopenharmony_ci	.name		= "stmmaceth",
2148c2ecf20Sopenharmony_ci	.id		= 1,
2158c2ecf20Sopenharmony_ci	.num_resources	= ARRAY_SIZE(ls1x_eth1_resources),
2168c2ecf20Sopenharmony_ci	.resource	= ls1x_eth1_resources,
2178c2ecf20Sopenharmony_ci	.dev		= {
2188c2ecf20Sopenharmony_ci		.platform_data = &ls1x_eth1_pdata,
2198c2ecf20Sopenharmony_ci	},
2208c2ecf20Sopenharmony_ci};
2218c2ecf20Sopenharmony_ci#endif	/* CONFIG_LOONGSON1_LS1B */
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci/* GPIO */
2248c2ecf20Sopenharmony_cistatic struct resource ls1x_gpio0_resources[] = {
2258c2ecf20Sopenharmony_ci	[0] = {
2268c2ecf20Sopenharmony_ci		.start	= LS1X_GPIO0_BASE,
2278c2ecf20Sopenharmony_ci		.end	= LS1X_GPIO0_BASE + SZ_4 - 1,
2288c2ecf20Sopenharmony_ci		.flags	= IORESOURCE_MEM,
2298c2ecf20Sopenharmony_ci	},
2308c2ecf20Sopenharmony_ci};
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistruct platform_device ls1x_gpio0_pdev = {
2338c2ecf20Sopenharmony_ci	.name		= "ls1x-gpio",
2348c2ecf20Sopenharmony_ci	.id		= 0,
2358c2ecf20Sopenharmony_ci	.num_resources	= ARRAY_SIZE(ls1x_gpio0_resources),
2368c2ecf20Sopenharmony_ci	.resource	= ls1x_gpio0_resources,
2378c2ecf20Sopenharmony_ci};
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_cistatic struct resource ls1x_gpio1_resources[] = {
2408c2ecf20Sopenharmony_ci	[0] = {
2418c2ecf20Sopenharmony_ci		.start	= LS1X_GPIO1_BASE,
2428c2ecf20Sopenharmony_ci		.end	= LS1X_GPIO1_BASE + SZ_4 - 1,
2438c2ecf20Sopenharmony_ci		.flags	= IORESOURCE_MEM,
2448c2ecf20Sopenharmony_ci	},
2458c2ecf20Sopenharmony_ci};
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cistruct platform_device ls1x_gpio1_pdev = {
2488c2ecf20Sopenharmony_ci	.name		= "ls1x-gpio",
2498c2ecf20Sopenharmony_ci	.id		= 1,
2508c2ecf20Sopenharmony_ci	.num_resources	= ARRAY_SIZE(ls1x_gpio1_resources),
2518c2ecf20Sopenharmony_ci	.resource	= ls1x_gpio1_resources,
2528c2ecf20Sopenharmony_ci};
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci/* USB EHCI */
2558c2ecf20Sopenharmony_cistatic u64 ls1x_ehci_dmamask = DMA_BIT_MASK(32);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_cistatic struct resource ls1x_ehci_resources[] = {
2588c2ecf20Sopenharmony_ci	[0] = {
2598c2ecf20Sopenharmony_ci		.start	= LS1X_EHCI_BASE,
2608c2ecf20Sopenharmony_ci		.end	= LS1X_EHCI_BASE + SZ_32K - 1,
2618c2ecf20Sopenharmony_ci		.flags	= IORESOURCE_MEM,
2628c2ecf20Sopenharmony_ci	},
2638c2ecf20Sopenharmony_ci	[1] = {
2648c2ecf20Sopenharmony_ci		.start	= LS1X_EHCI_IRQ,
2658c2ecf20Sopenharmony_ci		.flags	= IORESOURCE_IRQ,
2668c2ecf20Sopenharmony_ci	},
2678c2ecf20Sopenharmony_ci};
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_cistatic struct usb_ehci_pdata ls1x_ehci_pdata = {
2708c2ecf20Sopenharmony_ci};
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistruct platform_device ls1x_ehci_pdev = {
2738c2ecf20Sopenharmony_ci	.name		= "ehci-platform",
2748c2ecf20Sopenharmony_ci	.id		= -1,
2758c2ecf20Sopenharmony_ci	.num_resources	= ARRAY_SIZE(ls1x_ehci_resources),
2768c2ecf20Sopenharmony_ci	.resource	= ls1x_ehci_resources,
2778c2ecf20Sopenharmony_ci	.dev		= {
2788c2ecf20Sopenharmony_ci		.dma_mask = &ls1x_ehci_dmamask,
2798c2ecf20Sopenharmony_ci		.platform_data = &ls1x_ehci_pdata,
2808c2ecf20Sopenharmony_ci	},
2818c2ecf20Sopenharmony_ci};
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci/* Real Time Clock */
2848c2ecf20Sopenharmony_civoid __init ls1x_rtc_set_extclk(struct platform_device *pdev)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	u32 val = __raw_readl(LS1X_RTC_CTRL);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	if (!(val & RTC_EXTCLK_OK))
2898c2ecf20Sopenharmony_ci		__raw_writel(val | RTC_EXTCLK_EN, LS1X_RTC_CTRL);
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistruct platform_device ls1x_rtc_pdev = {
2938c2ecf20Sopenharmony_ci	.name		= "ls1x-rtc",
2948c2ecf20Sopenharmony_ci	.id		= -1,
2958c2ecf20Sopenharmony_ci};
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci/* Watchdog */
2988c2ecf20Sopenharmony_cistatic struct resource ls1x_wdt_resources[] = {
2998c2ecf20Sopenharmony_ci	{
3008c2ecf20Sopenharmony_ci		.start	= LS1X_WDT_BASE,
3018c2ecf20Sopenharmony_ci		.end	= LS1X_WDT_BASE + SZ_16 - 1,
3028c2ecf20Sopenharmony_ci		.flags	= IORESOURCE_MEM,
3038c2ecf20Sopenharmony_ci	},
3048c2ecf20Sopenharmony_ci};
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistruct platform_device ls1x_wdt_pdev = {
3078c2ecf20Sopenharmony_ci	.name		= "ls1x-wdt",
3088c2ecf20Sopenharmony_ci	.id		= -1,
3098c2ecf20Sopenharmony_ci	.num_resources	= ARRAY_SIZE(ls1x_wdt_resources),
3108c2ecf20Sopenharmony_ci	.resource	= ls1x_wdt_resources,
3118c2ecf20Sopenharmony_ci};
312