Add D-Link DNS-323 that is based on Device Tree. Signed-off-by: Mauri Sandberg <maukka@xxxxxxxxxxxx> --- changes from v1 - split patches, this one modifies source code - add DT based dns323 board file - don't remove any existing code --- arch/arm/mach-orion5x/Kconfig | 7 + arch/arm/mach-orion5x/Makefile | 1 + arch/arm/mach-orion5x/board-dns323.c | 208 +++++++++++++++++++++++++++ arch/arm/mach-orion5x/board-dt.c | 3 + arch/arm/mach-orion5x/common.h | 6 + 5 files changed, 225 insertions(+) create mode 100644 arch/arm/mach-orion5x/board-dns323.c diff --git a/arch/arm/mach-orion5x/Kconfig b/arch/arm/mach-orion5x/Kconfig index 0044b2823710..1ee0d7e06828 100644 --- a/arch/arm/mach-orion5x/Kconfig +++ b/arch/arm/mach-orion5x/Kconfig @@ -68,6 +68,13 @@ config MACH_DNS323 Say 'Y' here if you want your kernel to support the D-Link DNS-323 platform. +config MACH_DNS323_DT + bool "D-Link DNS-323 (Flattened Device Tree)" + select ARCH_ORION5X_DT + help + Say 'Y' here if you want your kernel to support the + D-Link DNS-323 platform. + config MACH_TS209 bool "QNAP TS-109/TS-209" depends on ATAGS diff --git a/arch/arm/mach-orion5x/Makefile b/arch/arm/mach-orion5x/Makefile index 1a585a62d5e6..2ed6bafa7acb 100644 --- a/arch/arm/mach-orion5x/Makefile +++ b/arch/arm/mach-orion5x/Makefile @@ -22,5 +22,6 @@ obj-$(CONFIG_MACH_RD88F6183AP_GE) += rd88f6183ap-ge-setup.o obj-$(CONFIG_ARCH_ORION5X_DT) += board-dt.o obj-$(CONFIG_MACH_D2NET_DT) += board-d2net.o +obj-$(CONFIG_MACH_DNS323_DT) += board-dns323.o obj-$(CONFIG_MACH_MSS2_DT) += board-mss2.o obj-$(CONFIG_MACH_RD88F5182_DT) += board-rd88f5182.o diff --git a/arch/arm/mach-orion5x/board-dns323.c b/arch/arm/mach-orion5x/board-dns323.c new file mode 100644 index 000000000000..72a1f3e228b3 --- /dev/null +++ b/arch/arm/mach-orion5x/board-dns323.c @@ -0,0 +1,208 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Mauri Sandberg <maukka@xxxxxxxxxxxx> + * + * Flattened Device Tree board initialization + * + * This is adapted from existing mach files and most of the source code is + * originally written by: + * Copyright (C) 2007 Herbert Valerio Riedel <hvr@xxxxxxx> + * Copyright (C) 2010 Benjamin Herrenschmidt <benh@xxxxxxxxxxxxxxxxxxx> + * Copyright 2012 (C), Jason Cooper <jason@xxxxxxxxxxxxxx> + */ + +#include <linux/of.h> +#include <linux/phy.h> +#include <linux/marvell_phy.h> +#include <linux/of_net.h> +#include <linux/clk.h> +#include "bridge-regs.h" + +/* Exposed to userspace, do not change */ +enum { + DNS323_REV_A1, /* 0 */ + DNS323_REV_B1, /* 1 */ + DNS323_REV_C1, /* 2 */ +}; + +/**************************************************************************** + * Fix-ups + */ + +static int dns323c_phy_fixup(struct phy_device *phy) +{ + phy->dev_flags |= MARVELL_PHY_M1118_DNS323_LEDS; + + return 0; +} + +/**************************************************************************** + * Ethernet + */ + +/* dns323_parse_hex_*() taken from tsx09-common.c; should a common copy of these + * functions be kept somewhere? + */ +static int __init dns323_parse_hex_nibble(char n) +{ + if (n >= '0' && n <= '9') + return n - '0'; + + if (n >= 'A' && n <= 'F') + return n - 'A' + 10; + + if (n >= 'a' && n <= 'f') + return n - 'a' + 10; + + return -1; +} + +static int __init dns323_parse_hex_byte(const char *b) +{ + int hi; + int lo; + + hi = dns323_parse_hex_nibble(b[0]); + lo = dns323_parse_hex_nibble(b[1]); + + if (hi < 0 || lo < 0) + return -1; + + return (hi << 4) | lo; +} + +#define DNS323_NOR_BOOT_BASE 0xf4000000 + +static int __init dns323_read_mac_addr(u8 *addr) +{ + int i; + char *mac_page; + + /* MAC address is stored as a regular ol' string in /dev/mtdblock4 + * (0x007d0000-0x00800000) starting at offset 196480 (0x2ff80). + */ + mac_page = ioremap(DNS323_NOR_BOOT_BASE + 0x7d0000 + 196480, 1024); + if (!mac_page) + return -ENOMEM; + + /* Sanity check the string we're looking at */ + for (i = 0; i < 5; i++) { + if (*(mac_page + (i * 3) + 2) != ':') + goto error_fail; + } + + for (i = 0; i < ETH_ALEN; i++) { + int byte; + + byte = dns323_parse_hex_byte(mac_page + (i * 3)); + if (byte < 0) + goto error_fail; + + addr[i] = byte; + } + + iounmap(mac_page); + + return 0; + +error_fail: + iounmap(mac_page); + return -EINVAL; +} + +static void __init dns323_dt_eth_fixup(void) +{ + struct device_node *np; + u8 addr[ETH_ALEN]; + int ret; + + /* + * The ethernet interfaces forget the MAC address assigned by u-boot + * if the clocks are turned off. Usually, u-boot on orion boards + * has no DT support to properly set local-mac-address property. + * As a workaround, we get the MAC address that is stored in flash + * and update the port device node if no valid MAC address is set. + */ + ret = dns323_read_mac_addr(addr); + + if (ret) { + pr_warn("Unable to find MAC address in flash memory\n"); + return; + } + + np = of_find_compatible_node(NULL, NULL, "marvell,orion-eth-port"); + + if (!IS_ERR(np)) { + struct device_node *pnp = of_get_parent(np); + struct clk *clk; + struct property *pmac; + u8 tmpmac[ETH_ALEN]; + u8 *macaddr; + int i; + + if (!pnp) + return; + + /* skip disabled nodes or nodes with valid MAC address*/ + if (!of_device_is_available(pnp) || + !of_get_mac_address(np, tmpmac)) + goto eth_fixup_skip; + + clk = of_clk_get(pnp, 0); + if (IS_ERR(clk)) + goto eth_fixup_skip; + + /* ensure port clock is not gated to not hang CPU */ + clk_prepare_enable(clk); + + /* store MAC address register contents in local-mac-address */ + pmac = kzalloc(sizeof(*pmac) + 6, GFP_KERNEL); + if (!pmac) + goto eth_fixup_no_mem; + + pmac->value = pmac + 1; + pmac->length = ETH_ALEN; + pmac->name = kstrdup("local-mac-address", GFP_KERNEL); + if (!pmac->name) { + kfree(pmac); + goto eth_fixup_no_mem; + } + + macaddr = pmac->value; + for (i = 0; i < ETH_ALEN; i++) + macaddr[i] = addr[i]; + + of_update_property(np, pmac); + +eth_fixup_no_mem: + clk_disable_unprepare(clk); + clk_put(clk); +eth_fixup_skip: + of_node_put(pnp); + } +} + +void __init dns323_init_dt(void) +{ + if (of_machine_is_compatible("dlink,dns323a1")) { + writel(0, MPP_DEV_CTRL); /* DEV_D[31:16] */ + } else if (of_machine_is_compatible("dlink,dns323c1") && + IS_BUILTIN(CONFIG_PHYLIB)) { + /* Register fixup for the PHY LEDs */ + phy_register_fixup_for_uid(MARVELL_PHY_ID_88E1118, + MARVELL_PHY_ID_MASK, + dns323c_phy_fixup); + + /* Now, -this- should theorically be done by the sata_mv driver + * once I figure out what's going on there. Maybe the behaviour + * of the LEDs should be somewhat passed via the platform_data. + * for now, just whack the register and make the LEDs happy + * + * Note: AFAIK, rev B1 needs the same treatement but I'll let + * somebody else test it. + */ + writel(0x5, ORION5X_SATA_VIRT_BASE + 0x2c); + } + + dns323_dt_eth_fixup(); +} diff --git a/arch/arm/mach-orion5x/board-dt.c b/arch/arm/mach-orion5x/board-dt.c index e3736ffc8347..670bff5e53f6 100644 --- a/arch/arm/mach-orion5x/board-dt.c +++ b/arch/arm/mach-orion5x/board-dt.c @@ -57,6 +57,9 @@ static void __init orion5x_dt_init(void) cpu_idle_poll_ctrl(true); } + if (of_machine_is_compatible("dlink,dns323")) + dns323_init_dt(); + if (of_machine_is_compatible("maxtor,shared-storage-2")) mss2_init(); diff --git a/arch/arm/mach-orion5x/common.h b/arch/arm/mach-orion5x/common.h index eb96009e21c4..7a21f7216c65 100644 --- a/arch/arm/mach-orion5x/common.h +++ b/arch/arm/mach-orion5x/common.h @@ -75,6 +75,12 @@ extern void mss2_init(void); static inline void mss2_init(void) {} #endif +#ifdef CONFIG_MACH_DNS323_DT +extern void dns323_init_dt(void); +#else +static inline void dns323_init_dt(void) {} +#endif + /***************************************************************************** * Helpers to access Orion registers ****************************************************************************/ -- 2.25.1