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