162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2011-2016 Zhang, Keguang <keguang.zhang@gmail.com>
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/clk.h>
762306a36Sopenharmony_ci#include <linux/dma-mapping.h>
862306a36Sopenharmony_ci#include <linux/err.h>
962306a36Sopenharmony_ci#include <linux/mtd/partitions.h>
1062306a36Sopenharmony_ci#include <linux/sizes.h>
1162306a36Sopenharmony_ci#include <linux/phy.h>
1262306a36Sopenharmony_ci#include <linux/serial_8250.h>
1362306a36Sopenharmony_ci#include <linux/stmmac.h>
1462306a36Sopenharmony_ci#include <linux/usb/ehci_pdriver.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <platform.h>
1762306a36Sopenharmony_ci#include <loongson1.h>
1862306a36Sopenharmony_ci#include <dma.h>
1962306a36Sopenharmony_ci#include <nand.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/* 8250/16550 compatible UART */
2262306a36Sopenharmony_ci#define LS1X_UART(_id)						\
2362306a36Sopenharmony_ci	{							\
2462306a36Sopenharmony_ci		.mapbase	= LS1X_UART ## _id ## _BASE,	\
2562306a36Sopenharmony_ci		.irq		= LS1X_UART ## _id ## _IRQ,	\
2662306a36Sopenharmony_ci		.iotype		= UPIO_MEM,			\
2762306a36Sopenharmony_ci		.flags		= UPF_IOREMAP | UPF_FIXED_TYPE, \
2862306a36Sopenharmony_ci		.type		= PORT_16550A,			\
2962306a36Sopenharmony_ci	}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic struct plat_serial8250_port ls1x_serial8250_pdata[] = {
3262306a36Sopenharmony_ci	LS1X_UART(0),
3362306a36Sopenharmony_ci	LS1X_UART(1),
3462306a36Sopenharmony_ci	LS1X_UART(2),
3562306a36Sopenharmony_ci	LS1X_UART(3),
3662306a36Sopenharmony_ci	{},
3762306a36Sopenharmony_ci};
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistruct platform_device ls1x_uart_pdev = {
4062306a36Sopenharmony_ci	.name		= "serial8250",
4162306a36Sopenharmony_ci	.id		= PLAT8250_DEV_PLATFORM,
4262306a36Sopenharmony_ci	.dev		= {
4362306a36Sopenharmony_ci		.platform_data = ls1x_serial8250_pdata,
4462306a36Sopenharmony_ci	},
4562306a36Sopenharmony_ci};
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_civoid __init ls1x_serial_set_uartclk(struct platform_device *pdev)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	struct clk *clk;
5062306a36Sopenharmony_ci	struct plat_serial8250_port *p;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	clk = clk_get(&pdev->dev, pdev->name);
5362306a36Sopenharmony_ci	if (IS_ERR(clk)) {
5462306a36Sopenharmony_ci		pr_err("unable to get %s clock, err=%ld",
5562306a36Sopenharmony_ci		       pdev->name, PTR_ERR(clk));
5662306a36Sopenharmony_ci		return;
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci	clk_prepare_enable(clk);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	for (p = pdev->dev.platform_data; p->flags != 0; ++p)
6162306a36Sopenharmony_ci		p->uartclk = clk_get_rate(clk);
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/* Synopsys Ethernet GMAC */
6562306a36Sopenharmony_cistatic struct stmmac_mdio_bus_data ls1x_mdio_bus_data = {
6662306a36Sopenharmony_ci	.phy_mask	= 0,
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic struct stmmac_dma_cfg ls1x_eth_dma_cfg = {
7062306a36Sopenharmony_ci	.pbl		= 1,
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ciint ls1x_eth_mux_init(struct platform_device *pdev, void *priv)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	struct plat_stmmacenet_data *plat_dat = NULL;
7662306a36Sopenharmony_ci	u32 val;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	val = __raw_readl(LS1X_MUX_CTRL1);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci#if defined(CONFIG_LOONGSON1_LS1B)
8162306a36Sopenharmony_ci	plat_dat = dev_get_platdata(&pdev->dev);
8262306a36Sopenharmony_ci	if (plat_dat->bus_id) {
8362306a36Sopenharmony_ci		__raw_writel(__raw_readl(LS1X_MUX_CTRL0) | GMAC1_USE_UART1 |
8462306a36Sopenharmony_ci			     GMAC1_USE_UART0, LS1X_MUX_CTRL0);
8562306a36Sopenharmony_ci		switch (plat_dat->phy_interface) {
8662306a36Sopenharmony_ci		case PHY_INTERFACE_MODE_RGMII:
8762306a36Sopenharmony_ci			val &= ~(GMAC1_USE_TXCLK | GMAC1_USE_PWM23);
8862306a36Sopenharmony_ci			break;
8962306a36Sopenharmony_ci		case PHY_INTERFACE_MODE_MII:
9062306a36Sopenharmony_ci			val |= (GMAC1_USE_TXCLK | GMAC1_USE_PWM23);
9162306a36Sopenharmony_ci			break;
9262306a36Sopenharmony_ci		default:
9362306a36Sopenharmony_ci			pr_err("unsupported mii mode %d\n",
9462306a36Sopenharmony_ci			       plat_dat->phy_interface);
9562306a36Sopenharmony_ci			return -ENOTSUPP;
9662306a36Sopenharmony_ci		}
9762306a36Sopenharmony_ci		val &= ~GMAC1_SHUT;
9862306a36Sopenharmony_ci	} else {
9962306a36Sopenharmony_ci		switch (plat_dat->phy_interface) {
10062306a36Sopenharmony_ci		case PHY_INTERFACE_MODE_RGMII:
10162306a36Sopenharmony_ci			val &= ~(GMAC0_USE_TXCLK | GMAC0_USE_PWM01);
10262306a36Sopenharmony_ci			break;
10362306a36Sopenharmony_ci		case PHY_INTERFACE_MODE_MII:
10462306a36Sopenharmony_ci			val |= (GMAC0_USE_TXCLK | GMAC0_USE_PWM01);
10562306a36Sopenharmony_ci			break;
10662306a36Sopenharmony_ci		default:
10762306a36Sopenharmony_ci			pr_err("unsupported mii mode %d\n",
10862306a36Sopenharmony_ci			       plat_dat->phy_interface);
10962306a36Sopenharmony_ci			return -ENOTSUPP;
11062306a36Sopenharmony_ci		}
11162306a36Sopenharmony_ci		val &= ~GMAC0_SHUT;
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci	__raw_writel(val, LS1X_MUX_CTRL1);
11462306a36Sopenharmony_ci#elif defined(CONFIG_LOONGSON1_LS1C)
11562306a36Sopenharmony_ci	plat_dat = dev_get_platdata(&pdev->dev);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	val &= ~PHY_INTF_SELI;
11862306a36Sopenharmony_ci	if (plat_dat->phy_interface == PHY_INTERFACE_MODE_RMII)
11962306a36Sopenharmony_ci		val |= 0x4 << PHY_INTF_SELI_SHIFT;
12062306a36Sopenharmony_ci	__raw_writel(val, LS1X_MUX_CTRL1);
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	val = __raw_readl(LS1X_MUX_CTRL0);
12362306a36Sopenharmony_ci	__raw_writel(val & (~GMAC_SHUT), LS1X_MUX_CTRL0);
12462306a36Sopenharmony_ci#endif
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	return 0;
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic struct plat_stmmacenet_data ls1x_eth0_pdata = {
13062306a36Sopenharmony_ci	.bus_id			= 0,
13162306a36Sopenharmony_ci	.phy_addr		= -1,
13262306a36Sopenharmony_ci#if defined(CONFIG_LOONGSON1_LS1B)
13362306a36Sopenharmony_ci	.phy_interface		= PHY_INTERFACE_MODE_MII,
13462306a36Sopenharmony_ci#elif defined(CONFIG_LOONGSON1_LS1C)
13562306a36Sopenharmony_ci	.phy_interface		= PHY_INTERFACE_MODE_RMII,
13662306a36Sopenharmony_ci#endif
13762306a36Sopenharmony_ci	.mdio_bus_data		= &ls1x_mdio_bus_data,
13862306a36Sopenharmony_ci	.dma_cfg		= &ls1x_eth_dma_cfg,
13962306a36Sopenharmony_ci	.has_gmac		= 1,
14062306a36Sopenharmony_ci	.tx_coe			= 1,
14162306a36Sopenharmony_ci	.rx_queues_to_use	= 1,
14262306a36Sopenharmony_ci	.tx_queues_to_use	= 1,
14362306a36Sopenharmony_ci	.init			= ls1x_eth_mux_init,
14462306a36Sopenharmony_ci};
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic struct resource ls1x_eth0_resources[] = {
14762306a36Sopenharmony_ci	[0] = {
14862306a36Sopenharmony_ci		.start	= LS1X_GMAC0_BASE,
14962306a36Sopenharmony_ci		.end	= LS1X_GMAC0_BASE + SZ_64K - 1,
15062306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,
15162306a36Sopenharmony_ci	},
15262306a36Sopenharmony_ci	[1] = {
15362306a36Sopenharmony_ci		.name	= "macirq",
15462306a36Sopenharmony_ci		.start	= LS1X_GMAC0_IRQ,
15562306a36Sopenharmony_ci		.flags	= IORESOURCE_IRQ,
15662306a36Sopenharmony_ci	},
15762306a36Sopenharmony_ci};
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistruct platform_device ls1x_eth0_pdev = {
16062306a36Sopenharmony_ci	.name		= "stmmaceth",
16162306a36Sopenharmony_ci	.id		= 0,
16262306a36Sopenharmony_ci	.num_resources	= ARRAY_SIZE(ls1x_eth0_resources),
16362306a36Sopenharmony_ci	.resource	= ls1x_eth0_resources,
16462306a36Sopenharmony_ci	.dev		= {
16562306a36Sopenharmony_ci		.platform_data = &ls1x_eth0_pdata,
16662306a36Sopenharmony_ci	},
16762306a36Sopenharmony_ci};
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci#ifdef CONFIG_LOONGSON1_LS1B
17062306a36Sopenharmony_cistatic struct plat_stmmacenet_data ls1x_eth1_pdata = {
17162306a36Sopenharmony_ci	.bus_id			= 1,
17262306a36Sopenharmony_ci	.phy_addr		= -1,
17362306a36Sopenharmony_ci	.phy_interface		= PHY_INTERFACE_MODE_MII,
17462306a36Sopenharmony_ci	.mdio_bus_data		= &ls1x_mdio_bus_data,
17562306a36Sopenharmony_ci	.dma_cfg		= &ls1x_eth_dma_cfg,
17662306a36Sopenharmony_ci	.has_gmac		= 1,
17762306a36Sopenharmony_ci	.tx_coe			= 1,
17862306a36Sopenharmony_ci	.rx_queues_to_use	= 1,
17962306a36Sopenharmony_ci	.tx_queues_to_use	= 1,
18062306a36Sopenharmony_ci	.init			= ls1x_eth_mux_init,
18162306a36Sopenharmony_ci};
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic struct resource ls1x_eth1_resources[] = {
18462306a36Sopenharmony_ci	[0] = {
18562306a36Sopenharmony_ci		.start	= LS1X_GMAC1_BASE,
18662306a36Sopenharmony_ci		.end	= LS1X_GMAC1_BASE + SZ_64K - 1,
18762306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,
18862306a36Sopenharmony_ci	},
18962306a36Sopenharmony_ci	[1] = {
19062306a36Sopenharmony_ci		.name	= "macirq",
19162306a36Sopenharmony_ci		.start	= LS1X_GMAC1_IRQ,
19262306a36Sopenharmony_ci		.flags	= IORESOURCE_IRQ,
19362306a36Sopenharmony_ci	},
19462306a36Sopenharmony_ci};
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cistruct platform_device ls1x_eth1_pdev = {
19762306a36Sopenharmony_ci	.name		= "stmmaceth",
19862306a36Sopenharmony_ci	.id		= 1,
19962306a36Sopenharmony_ci	.num_resources	= ARRAY_SIZE(ls1x_eth1_resources),
20062306a36Sopenharmony_ci	.resource	= ls1x_eth1_resources,
20162306a36Sopenharmony_ci	.dev		= {
20262306a36Sopenharmony_ci		.platform_data = &ls1x_eth1_pdata,
20362306a36Sopenharmony_ci	},
20462306a36Sopenharmony_ci};
20562306a36Sopenharmony_ci#endif	/* CONFIG_LOONGSON1_LS1B */
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci/* GPIO */
20862306a36Sopenharmony_cistatic struct resource ls1x_gpio0_resources[] = {
20962306a36Sopenharmony_ci	[0] = {
21062306a36Sopenharmony_ci		.start	= LS1X_GPIO0_BASE,
21162306a36Sopenharmony_ci		.end	= LS1X_GPIO0_BASE + SZ_4 - 1,
21262306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,
21362306a36Sopenharmony_ci	},
21462306a36Sopenharmony_ci};
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistruct platform_device ls1x_gpio0_pdev = {
21762306a36Sopenharmony_ci	.name		= "ls1x-gpio",
21862306a36Sopenharmony_ci	.id		= 0,
21962306a36Sopenharmony_ci	.num_resources	= ARRAY_SIZE(ls1x_gpio0_resources),
22062306a36Sopenharmony_ci	.resource	= ls1x_gpio0_resources,
22162306a36Sopenharmony_ci};
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic struct resource ls1x_gpio1_resources[] = {
22462306a36Sopenharmony_ci	[0] = {
22562306a36Sopenharmony_ci		.start	= LS1X_GPIO1_BASE,
22662306a36Sopenharmony_ci		.end	= LS1X_GPIO1_BASE + SZ_4 - 1,
22762306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,
22862306a36Sopenharmony_ci	},
22962306a36Sopenharmony_ci};
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistruct platform_device ls1x_gpio1_pdev = {
23262306a36Sopenharmony_ci	.name		= "ls1x-gpio",
23362306a36Sopenharmony_ci	.id		= 1,
23462306a36Sopenharmony_ci	.num_resources	= ARRAY_SIZE(ls1x_gpio1_resources),
23562306a36Sopenharmony_ci	.resource	= ls1x_gpio1_resources,
23662306a36Sopenharmony_ci};
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci/* USB EHCI */
23962306a36Sopenharmony_cistatic u64 ls1x_ehci_dmamask = DMA_BIT_MASK(32);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic struct resource ls1x_ehci_resources[] = {
24262306a36Sopenharmony_ci	[0] = {
24362306a36Sopenharmony_ci		.start	= LS1X_EHCI_BASE,
24462306a36Sopenharmony_ci		.end	= LS1X_EHCI_BASE + SZ_32K - 1,
24562306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,
24662306a36Sopenharmony_ci	},
24762306a36Sopenharmony_ci	[1] = {
24862306a36Sopenharmony_ci		.start	= LS1X_EHCI_IRQ,
24962306a36Sopenharmony_ci		.flags	= IORESOURCE_IRQ,
25062306a36Sopenharmony_ci	},
25162306a36Sopenharmony_ci};
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic struct usb_ehci_pdata ls1x_ehci_pdata = {
25462306a36Sopenharmony_ci};
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistruct platform_device ls1x_ehci_pdev = {
25762306a36Sopenharmony_ci	.name		= "ehci-platform",
25862306a36Sopenharmony_ci	.id		= -1,
25962306a36Sopenharmony_ci	.num_resources	= ARRAY_SIZE(ls1x_ehci_resources),
26062306a36Sopenharmony_ci	.resource	= ls1x_ehci_resources,
26162306a36Sopenharmony_ci	.dev		= {
26262306a36Sopenharmony_ci		.dma_mask = &ls1x_ehci_dmamask,
26362306a36Sopenharmony_ci		.platform_data = &ls1x_ehci_pdata,
26462306a36Sopenharmony_ci	},
26562306a36Sopenharmony_ci};
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci/* Real Time Clock */
26862306a36Sopenharmony_cistruct platform_device ls1x_rtc_pdev = {
26962306a36Sopenharmony_ci	.name		= "ls1x-rtc",
27062306a36Sopenharmony_ci	.id		= -1,
27162306a36Sopenharmony_ci};
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci/* Watchdog */
27462306a36Sopenharmony_cistatic struct resource ls1x_wdt_resources[] = {
27562306a36Sopenharmony_ci	{
27662306a36Sopenharmony_ci		.start	= LS1X_WDT_BASE,
27762306a36Sopenharmony_ci		.end	= LS1X_WDT_BASE + SZ_16 - 1,
27862306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,
27962306a36Sopenharmony_ci	},
28062306a36Sopenharmony_ci};
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistruct platform_device ls1x_wdt_pdev = {
28362306a36Sopenharmony_ci	.name		= "ls1x-wdt",
28462306a36Sopenharmony_ci	.id		= -1,
28562306a36Sopenharmony_ci	.num_resources	= ARRAY_SIZE(ls1x_wdt_resources),
28662306a36Sopenharmony_ci	.resource	= ls1x_wdt_resources,
28762306a36Sopenharmony_ci};
288