diff options
Diffstat (limited to 'target/linux/generic/files/drivers')
16 files changed, 886 insertions, 403 deletions
diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c index 3b71597d23..a271a676e1 100644 --- a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c @@ -278,7 +278,7 @@ mtdsplit_fit_parse(struct mtd_info *mtd, parts[0].name = KERNEL_PART_NAME; parts[0].offset = fit_offset; - parts[0].size = mtd_rounddown_to_eb(fit_size + offset_start, mtd) + mtd->erasesize; + parts[0].size = mtd_roundup_to_eb(fit_size + offset_start, mtd); if (type == MTDSPLIT_PART_TYPE_UBI) parts[1].name = UBI_PART_NAME; @@ -327,7 +327,7 @@ mtdsplit_fit_parse(struct mtd_info *mtd, return -ENOMEM; parts[0].name = ROOTFS_SPLIT_NAME; - parts[0].offset = fit_offset + mtd_rounddown_to_eb(max_size, mtd) + mtd->erasesize; + parts[0].offset = fit_offset + mtd_roundup_to_eb(max_size, mtd); parts[0].size = mtd->size - parts[0].offset; *pparts = parts; diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_minor.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_minor.c index af6822e11a..053cba6272 100644 --- a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_minor.c +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_minor.c @@ -34,7 +34,9 @@ #define YAFFS_OBJECT_TYPE_FILE 0x1 #define YAFFS_OBJECTID_ROOT 0x1 #define YAFFS_SUM_UNUSED 0xFFFF -#define YAFFS_NAME "kernel" +#define YAFFS_MAX_NAME_LENGTH 127 +#define YAFFS_NAME_KERNEL "kernel" +#define YAFFS_NAME_BOOTIMAGE "bootimage" #define MINOR_NR_PARTS 2 @@ -46,7 +48,7 @@ struct minor_header { int yaffs_type; int yaffs_obj_id; u16 yaffs_sum_unused; - char yaffs_name[sizeof(YAFFS_NAME)]; + char yaffs_name[YAFFS_MAX_NAME_LENGTH]; }; static int mtdsplit_parse_minor(struct mtd_info *master, @@ -61,29 +63,44 @@ static int mtdsplit_parse_minor(struct mtd_info *master, hdr_len = sizeof(hdr); err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); - if (err) + if (err) { + pr_err("MiNOR mtd_read error: %d\n", err); return err; + } - if (retlen != hdr_len) + if (retlen != hdr_len) { + pr_err("MiNOR mtd_read too short\n"); return -EIO; + } /* match header */ - if (hdr.yaffs_type != YAFFS_OBJECT_TYPE_FILE) - return -EINVAL; - - if (hdr.yaffs_obj_id != YAFFS_OBJECTID_ROOT) - return -EINVAL; - - if (hdr.yaffs_sum_unused != YAFFS_SUM_UNUSED) - return -EINVAL; - - if (memcmp(hdr.yaffs_name, YAFFS_NAME, sizeof(YAFFS_NAME))) - return -EINVAL; + if (hdr.yaffs_type != YAFFS_OBJECT_TYPE_FILE) { + pr_info("MiNOR YAFFS first type not matched\n"); + return 0; + } + + if (hdr.yaffs_obj_id != YAFFS_OBJECTID_ROOT) { + pr_info("MiNOR YAFFS first objectid not matched\n"); + return 0; + } + + if (hdr.yaffs_sum_unused != YAFFS_SUM_UNUSED) { + pr_info("MiNOR YAFFS first sum not matched\n"); + return 0; + } + + if ((memcmp(hdr.yaffs_name, YAFFS_NAME_KERNEL, sizeof(YAFFS_NAME_KERNEL))) && + (memcmp(hdr.yaffs_name, YAFFS_NAME_BOOTIMAGE, sizeof(YAFFS_NAME_BOOTIMAGE)))) { + pr_info("MiNOR YAFFS first name not matched\n"); + return 0; + } err = mtd_find_rootfs_from(master, master->erasesize, master->size, &rootfs_offset, NULL); - if (err) - return err; + if (err) { + pr_info("MiNOR mtd_find_rootfs_from error: %d\n", err); + return 0; + } parts = kzalloc(MINOR_NR_PARTS * sizeof(*parts), GFP_KERNEL); if (!parts) diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c b/target/linux/generic/files/drivers/net/phy/ar8216.c index 850bcefb74..84b923ffc1 100644 --- a/target/linux/generic/files/drivers/net/phy/ar8216.c +++ b/target/linux/generic/files/drivers/net/phy/ar8216.c @@ -35,7 +35,6 @@ #include <linux/lockdep.h> #include <linux/ar8216_platform.h> #include <linux/workqueue.h> -#include <linux/version.h> #include "ar8216.h" @@ -2458,11 +2457,7 @@ ar8xxx_phy_config_init(struct phy_device *phydev) /* VID fixup only needed on ar8216 */ if (chip_is_ar8216(priv)) { dev->phy_ptr = priv; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,1,0) dev->priv_flags |= IFF_NO_IP_ALIGN; -#else - dev->extra_priv_flags |= IFF_NO_IP_ALIGN; -#endif dev->eth_mangle_rx = ar8216_mangle_rx; dev->eth_mangle_tx = ar8216_mangle_tx; } @@ -2697,11 +2692,7 @@ ar8xxx_phy_detach(struct phy_device *phydev) #ifdef CONFIG_ETHERNET_PACKET_MANGLE dev->phy_ptr = NULL; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,1,0) dev->priv_flags &= ~IFF_NO_IP_ALIGN; -#else - dev->extra_priv_flags &= ~IFF_NO_IP_ALIGN; -#endif dev->eth_mangle_rx = NULL; dev->eth_mangle_tx = NULL; #endif diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366_smi.h b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.h index 3fcae81fa4..2608240bb0 100644 --- a/target/linux/generic/files/drivers/net/phy/rtl8366_smi.h +++ b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.h @@ -23,6 +23,18 @@ struct dentry; struct inode; struct file; +typedef enum rtl8367b_chip_e { + RTL8367B_CHIP_UNKNOWN, + /* Family B */ + RTL8367B_CHIP_RTL8367RB, + RTL8367B_CHIP_RTL8367R_VB, /* chip with exception in extif assignment */ +/* Family C */ + RTL8367B_CHIP_RTL8367RB_VB, + RTL8367B_CHIP_RTL8367S, +/* Family D */ + RTL8367B_CHIP_RTL8367S_VB /* chip with exception in extif assignment */ +} rtl8367b_chip_t; + struct rtl8366_mib_counter { unsigned base; unsigned offset; @@ -64,7 +76,9 @@ struct rtl8366_smi { u8 dbg_vlan_4k_page; #endif u32 phy_id; + rtl8367b_chip_t rtl8367b_chip; struct mii_bus *ext_mbus; + struct rtl8366_vlan_mc *emu_vlanmc; }; struct rtl8366_vlan_mc { diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366rb.c b/target/linux/generic/files/drivers/net/phy/rtl8366rb.c index 0e0116051a..0878ca9f14 100644 --- a/target/linux/generic/files/drivers/net/phy/rtl8366rb.c +++ b/target/linux/generic/files/drivers/net/phy/rtl8366rb.c @@ -1503,7 +1503,6 @@ MODULE_DEVICE_TABLE(of, rtl8366rb_match); static struct platform_driver rtl8366rb_driver = { .driver = { .name = RTL8366RB_DRIVER_NAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(rtl8366rb_match), }, .probe = rtl8366rb_probe, diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366s.c b/target/linux/generic/files/drivers/net/phy/rtl8366s.c index 8c746778b8..d4045fcc06 100644 --- a/target/linux/generic/files/drivers/net/phy/rtl8366s.c +++ b/target/linux/generic/files/drivers/net/phy/rtl8366s.c @@ -1291,7 +1291,6 @@ MODULE_DEVICE_TABLE(of, rtl8366s_match); static struct platform_driver rtl8366s_driver = { .driver = { .name = RTL8366S_DRIVER_NAME, - .owner = THIS_MODULE, #ifdef CONFIG_OF .of_match_table = of_match_ptr(rtl8366s_match), #endif diff --git a/target/linux/generic/files/drivers/net/phy/rtl8367.c b/target/linux/generic/files/drivers/net/phy/rtl8367.c index b14b63e036..950e9d2767 100644 --- a/target/linux/generic/files/drivers/net/phy/rtl8367.c +++ b/target/linux/generic/files/drivers/net/phy/rtl8367.c @@ -1077,21 +1077,37 @@ static int rtl8367_led_blinkrate_set(struct rtl8366_smi *smi, unsigned int rate) } #ifdef CONFIG_OF -static int rtl8367_extif_init_of(struct rtl8366_smi *smi, int id, +static int rtl8367_extif_init_of(struct rtl8366_smi *smi, const char *name) { struct rtl8367_extif_config *cfg; const __be32 *prop; int size; int err; + unsigned cpu_port; + unsigned id = UINT_MAX; prop = of_get_property(smi->parent->of_node, name, &size); - if (!prop) - return rtl8367_extif_init(smi, id, NULL); + if (!prop || (size != (10 * sizeof(*prop)))) { + dev_err(smi->parent, "%s property is not defined or invalid\n", name); + err = -EINVAL; + goto err_init; + } - if (size != (9 * sizeof(*prop))) { - dev_err(smi->parent, "%s property is invalid\n", name); - return -EINVAL; + cpu_port = be32_to_cpup(prop++); + switch (cpu_port) { + case RTL8367_CPU_PORT_NUM - 1: + case RTL8367_CPU_PORT_NUM: + id = RTL8367_CPU_PORT_NUM - cpu_port; + if (smi->cpu_port == UINT_MAX) { + dev_info(smi->parent, "cpu_port:%u, assigned to extif%u\n", cpu_port, id); + smi->cpu_port = cpu_port; + } + break; + default: + dev_err(smi->parent, "wrong cpu_port %u in %s property\n", cpu_port, name); + err = -EINVAL; + goto err_init; } cfg = kzalloc(sizeof(struct rtl8367_extif_config), GFP_KERNEL); @@ -1111,10 +1127,14 @@ static int rtl8367_extif_init_of(struct rtl8366_smi *smi, int id, err = rtl8367_extif_init(smi, id, cfg); kfree(cfg); +err_init: + if (id != 0) rtl8367_extif_init(smi, 0, NULL); + if (id != 1) rtl8367_extif_init(smi, 1, NULL); + return err; } #else -static int rtl8367_extif_init_of(struct rtl8366_smi *smi, int id, +static int rtl8367_extif_init_of(struct rtl8366_smi *smi, const char *name) { return -EINVAL; @@ -1135,11 +1155,7 @@ static int rtl8367_setup(struct rtl8366_smi *smi) /* initialize external interfaces */ if (smi->parent->of_node) { - err = rtl8367_extif_init_of(smi, 0, "realtek,extif0"); - if (err) - return err; - - err = rtl8367_extif_init_of(smi, 1, "realtek,extif1"); + err = rtl8367_extif_init_of(smi, "realtek,extif"); if (err) return err; } else { @@ -1722,11 +1738,6 @@ static int rtl8367_detect(struct rtl8366_smi *smi) dev_info(smi->parent, "RTL%s ver. %u chip found\n", chip_name, rtl_ver & RTL8367_RTL_VER_MASK); - if (of_property_present(smi->parent->of_node, "realtek,extif1")) - smi->cpu_port = RTL8367_CPU_PORT_NUM - 1; - - dev_info(smi->parent, "CPU port: %u\n", smi->cpu_port); - return 0; } @@ -1764,7 +1775,7 @@ static int rtl8367_probe(struct platform_device *pdev) smi->cmd_read = 0xb9; smi->cmd_write = 0xb8; smi->ops = &rtl8367_smi_ops; - smi->cpu_port = RTL8367_CPU_PORT_NUM; + smi->cpu_port = UINT_MAX; /* not defined yet */ smi->num_ports = RTL8367_NUM_PORTS; smi->num_vlan_mc = RTL8367_NUM_VLANS; smi->mib_counters = rtl8367_mib_counters; @@ -1823,7 +1834,6 @@ MODULE_DEVICE_TABLE(of, rtl8367_match); static struct platform_driver rtl8367_driver = { .driver = { .name = RTL8367_DRIVER_NAME, - .owner = THIS_MODULE, #ifdef CONFIG_OF .of_match_table = of_match_ptr(rtl8367_match), #endif diff --git a/target/linux/generic/files/drivers/net/phy/rtl8367b.c b/target/linux/generic/files/drivers/net/phy/rtl8367b.c index 04c790e924..5f885aa5be 100644 --- a/target/linux/generic/files/drivers/net/phy/rtl8367b.c +++ b/target/linux/generic/files/drivers/net/phy/rtl8367b.c @@ -1,5 +1,7 @@ /* - * Platform driver for the Realtek RTL8367R-VB ethernet switches + * Platform driver for Realtek RTL8367B family chips, i.e. RTL8367RB and RTL8367R-VB + * extended with support for RTL8367C family chips, i.e. RTL8367RB-VB and RTL8367S + * extended with support for RTL8367D family chips, i.e. RTL8367S-VB * * Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org> * @@ -266,6 +268,37 @@ struct rtl8367b_initval { #define RTL8367B_MIB_RXB_ID 0 /* IfInOctets */ #define RTL8367B_MIB_TXB_ID 28 /* IfOutOctets */ +#define RTL8367D_PORT_STATUS_REG(_p) (0x12d0 + (_p)) + +#define RTL8367D_PORT_STATUS_SPEED1_MASK 0x3000 +#define RTL8367D_PORT_STATUS_SPEED1_SHIFT 10 /*12-2*/ + +#define RTL8367D_REG_MAC0_FORCE_SELECT 0x12c0 +#define RTL8367D_REG_MAC0_FORCE_SELECT_EN 0x12c8 + +#define RTL8367D_VLAN_PVID_CTRL_REG(_p) (0x0700 + (_p)) +#define RTL8367D_VLAN_PVID_CTRL_MASK 0xfff +#define RTL8367D_VLAN_PVID_CTRL_SHIFT(_p) 0 + +#define RTL8367D_FIDMAX 3 +#define RTL8367D_FID_MASK 3 +#define RTL8367D_TA_VLAN1_FID_SHIFT 0 +#define RTL8367D_TA_VLAN1_FID_MASK RTL8367D_FID_MASK + +#define RTL8367D_VID_MASK 0xfff +#define RTL8367D_TA_VLAN_VID_MASK RTL8367D_VID_MASK + +#define RTL8367D_REG_EXT_TXC_DLY 0x13f9 +#define RTL8367D_EXT1_RGMII_TX_DLY_MASK 0x38 + +#define RTL8367D_REG_TOP_CON0 0x1d70 +#define RTL8367D_MAC7_SEL_EXT1_MASK 0x2000 +#define RTL8367D_MAC4_SEL_EXT1_MASK 0x1000 + +#define RTL8367D_REG_SDS1_MISC0 0x1d78 +#define RTL8367D_SDS1_MODE_MASK 0x1f +#define RTL8367D_PORT_SDS_MODE_DISABLE 0x1f + static struct rtl8366_mib_counter rtl8367b_mib_counters[RTL8367B_NUM_MIB_COUNTERS] = { {0, 0, 4, "ifInOctets" }, @@ -351,220 +384,7 @@ rtl8367b_mib_counters[RTL8367B_NUM_MIB_COUNTERS] = { return err; \ } while (0) -static const struct rtl8367b_initval rtl8367r_vb_initvals_0[] = { - {0x1B03, 0x0876}, {0x1200, 0x7FC4}, {0x0301, 0x0026}, {0x1722, 0x0E14}, - {0x205F, 0x0002}, {0x2059, 0x1A00}, {0x205F, 0x0000}, {0x207F, 0x0002}, - {0x2077, 0x0000}, {0x2078, 0x0000}, {0x2079, 0x0000}, {0x207A, 0x0000}, - {0x207B, 0x0000}, {0x207F, 0x0000}, {0x205F, 0x0002}, {0x2053, 0x0000}, - {0x2054, 0x0000}, {0x2055, 0x0000}, {0x2056, 0x0000}, {0x2057, 0x0000}, - {0x205F, 0x0000}, {0x12A4, 0x110A}, {0x12A6, 0x150A}, {0x13F1, 0x0013}, - {0x13F4, 0x0010}, {0x13F5, 0x0000}, {0x0018, 0x0F00}, {0x0038, 0x0F00}, - {0x0058, 0x0F00}, {0x0078, 0x0F00}, {0x0098, 0x0F00}, {0x12B6, 0x0C02}, - {0x12B7, 0x030F}, {0x12B8, 0x11FF}, {0x12BC, 0x0004}, {0x1362, 0x0115}, - {0x1363, 0x0002}, {0x1363, 0x0000}, {0x133F, 0x0030}, {0x133E, 0x000E}, - {0x221F, 0x0007}, {0x221E, 0x002D}, {0x2218, 0xF030}, {0x221F, 0x0007}, - {0x221E, 0x0023}, {0x2216, 0x0005}, {0x2215, 0x00B9}, {0x2219, 0x0044}, - {0x2215, 0x00BA}, {0x2219, 0x0020}, {0x2215, 0x00BB}, {0x2219, 0x00C1}, - {0x2215, 0x0148}, {0x2219, 0x0096}, {0x2215, 0x016E}, {0x2219, 0x0026}, - {0x2216, 0x0000}, {0x2216, 0x0000}, {0x221E, 0x002D}, {0x2218, 0xF010}, - {0x221F, 0x0007}, {0x221E, 0x0020}, {0x2215, 0x0D00}, {0x221F, 0x0000}, - {0x221F, 0x0000}, {0x2217, 0x2160}, {0x221F, 0x0001}, {0x2210, 0xF25E}, - {0x221F, 0x0007}, {0x221E, 0x0042}, {0x2215, 0x0F00}, {0x2215, 0x0F00}, - {0x2216, 0x7408}, {0x2215, 0x0E00}, {0x2215, 0x0F00}, {0x2215, 0x0F01}, - {0x2216, 0x4000}, {0x2215, 0x0E01}, {0x2215, 0x0F01}, {0x2215, 0x0F02}, - {0x2216, 0x9400}, {0x2215, 0x0E02}, {0x2215, 0x0F02}, {0x2215, 0x0F03}, - {0x2216, 0x7408}, {0x2215, 0x0E03}, {0x2215, 0x0F03}, {0x2215, 0x0F04}, - {0x2216, 0x4008}, {0x2215, 0x0E04}, {0x2215, 0x0F04}, {0x2215, 0x0F05}, - {0x2216, 0x9400}, {0x2215, 0x0E05}, {0x2215, 0x0F05}, {0x2215, 0x0F06}, - {0x2216, 0x0803}, {0x2215, 0x0E06}, {0x2215, 0x0F06}, {0x2215, 0x0D00}, - {0x2215, 0x0100}, {0x221F, 0x0001}, {0x2210, 0xF05E}, {0x221F, 0x0000}, - {0x2217, 0x2100}, {0x221F, 0x0000}, {0x220D, 0x0003}, {0x220E, 0x0015}, - {0x220D, 0x4003}, {0x220E, 0x0006}, {0x221F, 0x0000}, {0x2200, 0x1340}, - {0x133F, 0x0010}, {0x12A0, 0x0058}, {0x12A1, 0x0058}, {0x133E, 0x000E}, - {0x133F, 0x0030}, {0x221F, 0x0000}, {0x2210, 0x0166}, {0x221F, 0x0000}, - {0x133E, 0x000E}, {0x133F, 0x0010}, {0x133F, 0x0030}, {0x133E, 0x000E}, - {0x221F, 0x0005}, {0x2205, 0xFFF6}, {0x2206, 0x0080}, {0x2205, 0x8B6E}, - {0x2206, 0x0000}, {0x220F, 0x0100}, {0x2205, 0x8000}, {0x2206, 0x0280}, - {0x2206, 0x28F7}, {0x2206, 0x00E0}, {0x2206, 0xFFF7}, {0x2206, 0xA080}, - {0x2206, 0x02AE}, {0x2206, 0xF602}, {0x2206, 0x0153}, {0x2206, 0x0201}, - {0x2206, 0x6602}, {0x2206, 0x80B9}, {0x2206, 0xE08B}, {0x2206, 0x8CE1}, - {0x2206, 0x8B8D}, {0x2206, 0x1E01}, {0x2206, 0xE18B}, {0x2206, 0x8E1E}, - {0x2206, 0x01A0}, {0x2206, 0x00E7}, {0x2206, 0xAEDB}, {0x2206, 0xEEE0}, - {0x2206, 0x120E}, {0x2206, 0xEEE0}, {0x2206, 0x1300}, {0x2206, 0xEEE0}, - {0x2206, 0x2001}, {0x2206, 0xEEE0}, {0x2206, 0x2166}, {0x2206, 0xEEE0}, - {0x2206, 0xC463}, {0x2206, 0xEEE0}, {0x2206, 0xC5E8}, {0x2206, 0xEEE0}, - {0x2206, 0xC699}, {0x2206, 0xEEE0}, {0x2206, 0xC7C2}, {0x2206, 0xEEE0}, - {0x2206, 0xC801}, {0x2206, 0xEEE0}, {0x2206, 0xC913}, {0x2206, 0xEEE0}, - {0x2206, 0xCA30}, {0x2206, 0xEEE0}, {0x2206, 0xCB3E}, {0x2206, 0xEEE0}, - {0x2206, 0xDCE1}, {0x2206, 0xEEE0}, {0x2206, 0xDD00}, {0x2206, 0xEEE2}, - {0x2206, 0x0001}, {0x2206, 0xEEE2}, {0x2206, 0x0100}, {0x2206, 0xEEE4}, - {0x2206, 0x8860}, {0x2206, 0xEEE4}, {0x2206, 0x8902}, {0x2206, 0xEEE4}, - {0x2206, 0x8C00}, {0x2206, 0xEEE4}, {0x2206, 0x8D30}, {0x2206, 0xEEEA}, - {0x2206, 0x1480}, {0x2206, 0xEEEA}, {0x2206, 0x1503}, {0x2206, 0xEEEA}, - {0x2206, 0xC600}, {0x2206, 0xEEEA}, {0x2206, 0xC706}, {0x2206, 0xEE85}, - {0x2206, 0xEE00}, {0x2206, 0xEE85}, {0x2206, 0xEF00}, {0x2206, 0xEE8B}, - {0x2206, 0x6750}, {0x2206, 0xEE8B}, {0x2206, 0x6632}, {0x2206, 0xEE8A}, - {0x2206, 0xD448}, {0x2206, 0xEE8A}, {0x2206, 0xD548}, {0x2206, 0xEE8A}, - {0x2206, 0xD649}, {0x2206, 0xEE8A}, {0x2206, 0xD7F8}, {0x2206, 0xEE8B}, - {0x2206, 0x85E2}, {0x2206, 0xEE8B}, {0x2206, 0x8700}, {0x2206, 0xEEFF}, - {0x2206, 0xF600}, {0x2206, 0xEEFF}, {0x2206, 0xF7FC}, {0x2206, 0x04F8}, - {0x2206, 0xE08B}, {0x2206, 0x8EAD}, {0x2206, 0x2023}, {0x2206, 0xF620}, - {0x2206, 0xE48B}, {0x2206, 0x8E02}, {0x2206, 0x2877}, {0x2206, 0x0225}, - {0x2206, 0xC702}, {0x2206, 0x26A1}, {0x2206, 0x0281}, {0x2206, 0xB302}, - {0x2206, 0x8496}, {0x2206, 0x0202}, {0x2206, 0xA102}, {0x2206, 0x27F1}, - {0x2206, 0x0228}, {0x2206, 0xF902}, {0x2206, 0x2AA0}, {0x2206, 0x0282}, - {0x2206, 0xB8E0}, {0x2206, 0x8B8E}, {0x2206, 0xAD21}, {0x2206, 0x08F6}, - {0x2206, 0x21E4}, {0x2206, 0x8B8E}, {0x2206, 0x0202}, {0x2206, 0x80E0}, - {0x2206, 0x8B8E}, {0x2206, 0xAD22}, {0x2206, 0x05F6}, {0x2206, 0x22E4}, - {0x2206, 0x8B8E}, {0x2206, 0xE08B}, {0x2206, 0x8EAD}, {0x2206, 0x2305}, - {0x2206, 0xF623}, {0x2206, 0xE48B}, {0x2206, 0x8EE0}, {0x2206, 0x8B8E}, - {0x2206, 0xAD24}, {0x2206, 0x08F6}, {0x2206, 0x24E4}, {0x2206, 0x8B8E}, - {0x2206, 0x0227}, {0x2206, 0x6AE0}, {0x2206, 0x8B8E}, {0x2206, 0xAD25}, - {0x2206, 0x05F6}, {0x2206, 0x25E4}, {0x2206, 0x8B8E}, {0x2206, 0xE08B}, - {0x2206, 0x8EAD}, {0x2206, 0x260B}, {0x2206, 0xF626}, {0x2206, 0xE48B}, - {0x2206, 0x8E02}, {0x2206, 0x830D}, {0x2206, 0x021D}, {0x2206, 0x6BE0}, - {0x2206, 0x8B8E}, {0x2206, 0xAD27}, {0x2206, 0x05F6}, {0x2206, 0x27E4}, - {0x2206, 0x8B8E}, {0x2206, 0x0281}, {0x2206, 0x4402}, {0x2206, 0x045C}, - {0x2206, 0xFC04}, {0x2206, 0xF8E0}, {0x2206, 0x8B83}, {0x2206, 0xAD23}, - {0x2206, 0x30E0}, {0x2206, 0xE022}, {0x2206, 0xE1E0}, {0x2206, 0x2359}, - {0x2206, 0x02E0}, {0x2206, 0x85EF}, {0x2206, 0xE585}, {0x2206, 0xEFAC}, - {0x2206, 0x2907}, {0x2206, 0x1F01}, {0x2206, 0x9E51}, {0x2206, 0xAD29}, - {0x2206, 0x20E0}, {0x2206, 0x8B83}, {0x2206, 0xAD21}, {0x2206, 0x06E1}, - {0x2206, 0x8B84}, {0x2206, 0xAD28}, {0x2206, 0x42E0}, {0x2206, 0x8B85}, - {0x2206, 0xAD21}, {0x2206, 0x06E1}, {0x2206, 0x8B84}, {0x2206, 0xAD29}, - {0x2206, 0x36BF}, {0x2206, 0x34BF}, {0x2206, 0x022C}, {0x2206, 0x31AE}, - {0x2206, 0x2EE0}, {0x2206, 0x8B83}, {0x2206, 0xAD21}, {0x2206, 0x10E0}, - {0x2206, 0x8B84}, {0x2206, 0xF620}, {0x2206, 0xE48B}, {0x2206, 0x84EE}, - {0x2206, 0x8ADA}, {0x2206, 0x00EE}, {0x2206, 0x8ADB}, {0x2206, 0x00E0}, - {0x2206, 0x8B85}, {0x2206, 0xAD21}, {0x2206, 0x0CE0}, {0x2206, 0x8B84}, - {0x2206, 0xF621}, {0x2206, 0xE48B}, {0x2206, 0x84EE}, {0x2206, 0x8B72}, - {0x2206, 0xFFBF}, {0x2206, 0x34C2}, {0x2206, 0x022C}, {0x2206, 0x31FC}, - {0x2206, 0x04F8}, {0x2206, 0xFAEF}, {0x2206, 0x69E0}, {0x2206, 0x8B85}, - {0x2206, 0xAD21}, {0x2206, 0x42E0}, {0x2206, 0xE022}, {0x2206, 0xE1E0}, - {0x2206, 0x2358}, {0x2206, 0xC059}, {0x2206, 0x021E}, {0x2206, 0x01E1}, - {0x2206, 0x8B72}, {0x2206, 0x1F10}, {0x2206, 0x9E2F}, {0x2206, 0xE48B}, - {0x2206, 0x72AD}, {0x2206, 0x2123}, {0x2206, 0xE18B}, {0x2206, 0x84F7}, - {0x2206, 0x29E5}, {0x2206, 0x8B84}, {0x2206, 0xAC27}, {0x2206, 0x10AC}, - {0x2206, 0x2605}, {0x2206, 0x0205}, {0x2206, 0x23AE}, {0x2206, 0x1602}, - {0x2206, 0x0535}, {0x2206, 0x0282}, {0x2206, 0x30AE}, {0x2206, 0x0E02}, - {0x2206, 0x056A}, {0x2206, 0x0282}, {0x2206, 0x75AE}, {0x2206, 0x0602}, - {0x2206, 0x04DC}, {0x2206, 0x0282}, {0x2206, 0x04EF}, {0x2206, 0x96FE}, - {0x2206, 0xFC04}, {0x2206, 0xF8F9}, {0x2206, 0xE08B}, {0x2206, 0x87AD}, - {0x2206, 0x2321}, {0x2206, 0xE0EA}, {0x2206, 0x14E1}, {0x2206, 0xEA15}, - {0x2206, 0xAD26}, {0x2206, 0x18F6}, {0x2206, 0x27E4}, {0x2206, 0xEA14}, - {0x2206, 0xE5EA}, {0x2206, 0x15F6}, {0x2206, 0x26E4}, {0x2206, 0xEA14}, - {0x2206, 0xE5EA}, {0x2206, 0x15F7}, {0x2206, 0x27E4}, {0x2206, 0xEA14}, - {0x2206, 0xE5EA}, {0x2206, 0x15FD}, {0x2206, 0xFC04}, {0x2206, 0xF8F9}, - {0x2206, 0xE08B}, {0x2206, 0x87AD}, {0x2206, 0x233A}, {0x2206, 0xAD22}, - {0x2206, 0x37E0}, {0x2206, 0xE020}, {0x2206, 0xE1E0}, {0x2206, 0x21AC}, - {0x2206, 0x212E}, {0x2206, 0xE0EA}, {0x2206, 0x14E1}, {0x2206, 0xEA15}, - {0x2206, 0xF627}, {0x2206, 0xE4EA}, {0x2206, 0x14E5}, {0x2206, 0xEA15}, - {0x2206, 0xE2EA}, {0x2206, 0x12E3}, {0x2206, 0xEA13}, {0x2206, 0x5A8F}, - {0x2206, 0x6A20}, {0x2206, 0xE6EA}, {0x2206, 0x12E7}, {0x2206, 0xEA13}, - {0x2206, 0xF726}, {0x2206, 0xE4EA}, {0x2206, 0x14E5}, {0x2206, 0xEA15}, - {0x2206, 0xF727}, {0x2206, 0xE4EA}, {0x2206, 0x14E5}, {0x2206, 0xEA15}, - {0x2206, 0xFDFC}, {0x2206, 0x04F8}, {0x2206, 0xF9E0}, {0x2206, 0x8B87}, - {0x2206, 0xAD23}, {0x2206, 0x38AD}, {0x2206, 0x2135}, {0x2206, 0xE0E0}, - {0x2206, 0x20E1}, {0x2206, 0xE021}, {0x2206, 0xAC21}, {0x2206, 0x2CE0}, - {0x2206, 0xEA14}, {0x2206, 0xE1EA}, {0x2206, 0x15F6}, {0x2206, 0x27E4}, - {0x2206, 0xEA14}, {0x2206, 0xE5EA}, {0x2206, 0x15E2}, {0x2206, 0xEA12}, - {0x2206, 0xE3EA}, {0x2206, 0x135A}, {0x2206, 0x8FE6}, {0x2206, 0xEA12}, - {0x2206, 0xE7EA}, {0x2206, 0x13F7}, {0x2206, 0x26E4}, {0x2206, 0xEA14}, - {0x2206, 0xE5EA}, {0x2206, 0x15F7}, {0x2206, 0x27E4}, {0x2206, 0xEA14}, - {0x2206, 0xE5EA}, {0x2206, 0x15FD}, {0x2206, 0xFC04}, {0x2206, 0xF8FA}, - {0x2206, 0xEF69}, {0x2206, 0xE08B}, {0x2206, 0x86AD}, {0x2206, 0x2146}, - {0x2206, 0xE0E0}, {0x2206, 0x22E1}, {0x2206, 0xE023}, {0x2206, 0x58C0}, - {0x2206, 0x5902}, {0x2206, 0x1E01}, {0x2206, 0xE18B}, {0x2206, 0x651F}, - {0x2206, 0x109E}, {0x2206, 0x33E4}, {0x2206, 0x8B65}, {0x2206, 0xAD21}, - {0x2206, 0x22AD}, {0x2206, 0x272A}, {0x2206, 0xD400}, {0x2206, 0x01BF}, - {0x2206, 0x34F2}, {0x2206, 0x022C}, {0x2206, 0xA2BF}, {0x2206, 0x34F5}, - {0x2206, 0x022C}, {0x2206, 0xE0E0}, {0x2206, 0x8B67}, {0x2206, 0x1B10}, - {0x2206, 0xAA14}, {0x2206, 0xE18B}, {0x2206, 0x660D}, {0x2206, 0x1459}, - {0x2206, 0x0FAE}, {0x2206, 0x05E1}, {0x2206, 0x8B66}, {0x2206, 0x590F}, - {0x2206, 0xBF85}, {0x2206, 0x6102}, {0x2206, 0x2CA2}, {0x2206, 0xEF96}, - {0x2206, 0xFEFC}, {0x2206, 0x04F8}, {0x2206, 0xF9FA}, {0x2206, 0xFBEF}, - {0x2206, 0x79E2}, {0x2206, 0x8AD2}, {0x2206, 0xAC19}, {0x2206, 0x2DE0}, - {0x2206, 0xE036}, {0x2206, 0xE1E0}, {0x2206, 0x37EF}, {0x2206, 0x311F}, - {0x2206, 0x325B}, {0x2206, 0x019E}, {0x2206, 0x1F7A}, {0x2206, 0x0159}, - {0x2206, 0x019F}, {0x2206, 0x0ABF}, {0x2206, 0x348E}, {0x2206, 0x022C}, - {0x2206, 0x31F6}, {0x2206, 0x06AE}, {0x2206, 0x0FF6}, {0x2206, 0x0302}, - {0x2206, 0x0470}, {0x2206, 0xF703}, {0x2206, 0xF706}, {0x2206, 0xBF34}, - {0x2206, 0x9302}, {0x2206, 0x2C31}, {0x2206, 0xAC1A}, {0x2206, 0x25E0}, - {0x2206, 0xE022}, {0x2206, 0xE1E0}, {0x2206, 0x23EF}, {0x2206, 0x300D}, - {0x2206, 0x311F}, {0x2206, 0x325B}, {0x2206, 0x029E}, {0x2206, 0x157A}, - {0x2206, 0x0258}, {0x2206, 0xC4A0}, {0x2206, 0x0408}, {0x2206, 0xBF34}, - {0x2206, 0x9E02}, {0x2206, 0x2C31}, {0x2206, 0xAE06}, {0x2206, 0xBF34}, - {0x2206, 0x9C02}, {0x2206, 0x2C31}, {0x2206, 0xAC1B}, {0x2206, 0x4AE0}, - {0x2206, 0xE012}, {0x2206, 0xE1E0}, {0x2206, 0x13EF}, {0x2206, 0x300D}, - {0x2206, 0x331F}, {0x2206, 0x325B}, {0x2206, 0x1C9E}, {0x2206, 0x3AEF}, - {0x2206, 0x325B}, {0x2206, 0x1C9F}, {0x2206, 0x09BF}, {0x2206, 0x3498}, - {0x2206, 0x022C}, {0x2206, 0x3102}, {0x2206, 0x83C5}, {0x2206, 0x5A03}, - {0x2206, 0x0D03}, {0x2206, 0x581C}, {0x2206, 0x1E20}, {0x2206, 0x0207}, - {0x2206, 0xA0A0}, {0x2206, 0x000E}, {0x2206, 0x0284}, {0x2206, 0x17AD}, - {0x2206, 0x1817}, {0x2206, 0xBF34}, {0x2206, 0x9A02}, {0x2206, 0x2C31}, - {0x2206, 0xAE0F}, {0x2206, 0xBF34}, {0x2206, 0xC802}, {0x2206, 0x2C31}, - {0x2206, 0xBF34}, {0x2206, 0xC502}, {0x2206, 0x2C31}, {0x2206, 0x0284}, - {0x2206, 0x52E6}, {0x2206, 0x8AD2}, {0x2206, 0xEF97}, {0x2206, 0xFFFE}, - {0x2206, 0xFDFC}, {0x2206, 0x04F8}, {0x2206, 0xBF34}, {0x2206, 0xDA02}, - {0x2206, 0x2CE0}, {0x2206, 0xE58A}, {0x2206, 0xD3BF}, {0x2206, 0x34D4}, - {0x2206, 0x022C}, {0x2206, 0xE00C}, {0x2206, 0x1159}, {0x2206, 0x02E0}, - {0x2206, 0x8AD3}, {0x2206, 0x1E01}, {0x2206, 0xE48A}, {0x2206, 0xD3D1}, - {0x2206, 0x00BF}, {0x2206, 0x34DA}, {0x2206, 0x022C}, {0x2206, 0xA2D1}, - {0x2206, 0x01BF}, {0x2206, 0x34D4}, {0x2206, 0x022C}, {0x2206, 0xA2BF}, - {0x2206, 0x34CB}, {0x2206, 0x022C}, {0x2206, 0xE0E5}, {0x2206, 0x8ACE}, - {0x2206, 0xBF85}, {0x2206, 0x6702}, {0x2206, 0x2CE0}, {0x2206, 0xE58A}, - {0x2206, 0xCFBF}, {0x2206, 0x8564}, {0x2206, 0x022C}, {0x2206, 0xE0E5}, - {0x2206, 0x8AD0}, {0x2206, 0xBF85}, {0x2206, 0x6A02}, {0x2206, 0x2CE0}, - {0x2206, 0xE58A}, {0x2206, 0xD1FC}, {0x2206, 0x04F8}, {0x2206, 0xE18A}, - {0x2206, 0xD1BF}, {0x2206, 0x856A}, {0x2206, 0x022C}, {0x2206, 0xA2E1}, - {0x2206, 0x8AD0}, {0x2206, 0xBF85}, {0x2206, 0x6402}, {0x2206, 0x2CA2}, - {0x2206, 0xE18A}, {0x2206, 0xCFBF}, {0x2206, 0x8567}, {0x2206, 0x022C}, - {0x2206, 0xA2E1}, {0x2206, 0x8ACE}, {0x2206, 0xBF34}, {0x2206, 0xCB02}, - {0x2206, 0x2CA2}, {0x2206, 0xE18A}, {0x2206, 0xD3BF}, {0x2206, 0x34DA}, - {0x2206, 0x022C}, {0x2206, 0xA2E1}, {0x2206, 0x8AD3}, {0x2206, 0x0D11}, - {0x2206, 0xBF34}, {0x2206, 0xD402}, {0x2206, 0x2CA2}, {0x2206, 0xFC04}, - {0x2206, 0xF9A0}, {0x2206, 0x0405}, {0x2206, 0xE38A}, {0x2206, 0xD4AE}, - {0x2206, 0x13A0}, {0x2206, 0x0805}, {0x2206, 0xE38A}, {0x2206, 0xD5AE}, - {0x2206, 0x0BA0}, {0x2206, 0x0C05}, {0x2206, 0xE38A}, {0x2206, 0xD6AE}, - {0x2206, 0x03E3}, {0x2206, 0x8AD7}, {0x2206, 0xEF13}, {0x2206, 0xBF34}, - {0x2206, 0xCB02}, {0x2206, 0x2CA2}, {0x2206, 0xEF13}, {0x2206, 0x0D11}, - {0x2206, 0xBF85}, {0x2206, 0x6702}, {0x2206, 0x2CA2}, {0x2206, 0xEF13}, - {0x2206, 0x0D14}, {0x2206, 0xBF85}, {0x2206, 0x6402}, {0x2206, 0x2CA2}, - {0x2206, 0xEF13}, {0x2206, 0x0D17}, {0x2206, 0xBF85}, {0x2206, 0x6A02}, - {0x2206, 0x2CA2}, {0x2206, 0xFD04}, {0x2206, 0xF8E0}, {0x2206, 0x8B85}, - {0x2206, 0xAD27}, {0x2206, 0x2DE0}, {0x2206, 0xE036}, {0x2206, 0xE1E0}, - {0x2206, 0x37E1}, {0x2206, 0x8B73}, {0x2206, 0x1F10}, {0x2206, 0x9E20}, - {0x2206, 0xE48B}, {0x2206, 0x73AC}, {0x2206, 0x200B}, {0x2206, 0xAC21}, - {0x2206, 0x0DAC}, {0x2206, 0x250F}, {0x2206, 0xAC27}, {0x2206, 0x0EAE}, - {0x2206, 0x0F02}, {0x2206, 0x84CC}, {0x2206, 0xAE0A}, {0x2206, 0x0284}, - {0x2206, 0xD1AE}, {0x2206, 0x05AE}, {0x2206, 0x0302}, {0x2206, 0x84D8}, - {0x2206, 0xFC04}, {0x2206, 0xEE8B}, {0x2206, 0x6800}, {0x2206, 0x0402}, - {0x2206, 0x84E5}, {0x2206, 0x0285}, {0x2206, 0x2804}, {0x2206, 0x0285}, - {0x2206, 0x4904}, {0x2206, 0xEE8B}, {0x2206, 0x6800}, {0x2206, 0xEE8B}, - {0x2206, 0x6902}, {0x2206, 0x04F8}, {0x2206, 0xF9E0}, {0x2206, 0x8B85}, - {0x2206, 0xAD26}, {0x2206, 0x38D0}, {0x2206, 0x0B02}, {0x2206, 0x2B4D}, - {0x2206, 0x5882}, {0x2206, 0x7882}, {0x2206, 0x9F2D}, {0x2206, 0xE08B}, - {0x2206, 0x68E1}, {0x2206, 0x8B69}, {0x2206, 0x1F10}, {0x2206, 0x9EC8}, - {0x2206, 0x10E4}, {0x2206, 0x8B68}, {0x2206, 0xE0E0}, {0x2206, 0x00E1}, - {0x2206, 0xE001}, {0x2206, 0xF727}, {0x2206, 0xE4E0}, {0x2206, 0x00E5}, - {0x2206, 0xE001}, {0x2206, 0xE2E0}, {0x2206, 0x20E3}, {0x2206, 0xE021}, - {0x2206, 0xAD30}, {0x2206, 0xF7F6}, {0x2206, 0x27E4}, {0x2206, 0xE000}, - {0x2206, 0xE5E0}, {0x2206, 0x01FD}, {0x2206, 0xFC04}, {0x2206, 0xF8FA}, - {0x2206, 0xEF69}, {0x2206, 0xE08B}, {0x2206, 0x86AD}, {0x2206, 0x2212}, - {0x2206, 0xE0E0}, {0x2206, 0x14E1}, {0x2206, 0xE015}, {0x2206, 0xAD26}, - {0x2206, 0x9CE1}, {0x2206, 0x85E0}, {0x2206, 0xBF85}, {0x2206, 0x6D02}, - {0x2206, 0x2CA2}, {0x2206, 0xEF96}, {0x2206, 0xFEFC}, {0x2206, 0x04F8}, - {0x2206, 0xFAEF}, {0x2206, 0x69E0}, {0x2206, 0x8B86}, {0x2206, 0xAD22}, - {0x2206, 0x09E1}, {0x2206, 0x85E1}, {0x2206, 0xBF85}, {0x2206, 0x6D02}, - {0x2206, 0x2CA2}, {0x2206, 0xEF96}, {0x2206, 0xFEFC}, {0x2206, 0x0464}, - {0x2206, 0xE48C}, {0x2206, 0xFDE4}, {0x2206, 0x80CA}, {0x2206, 0xE480}, - {0x2206, 0x66E0}, {0x2206, 0x8E70}, {0x2206, 0xE076}, {0x2205, 0xE142}, - {0x2206, 0x0701}, {0x2205, 0xE140}, {0x2206, 0x0405}, {0x220F, 0x0000}, - {0x221F, 0x0000}, {0x2200, 0x1340}, {0x133E, 0x000E}, {0x133F, 0x0010}, - {0x13EB, 0x11BB} -}; - -static const struct rtl8367b_initval rtl8367r_vb_initvals_1[] = { +static const struct rtl8367b_initval rtl8367b_initvals[] = { {0x1B03, 0x0876}, {0x1200, 0x7FC4}, {0x1305, 0xC000}, {0x121E, 0x03CA}, {0x1233, 0x0352}, {0x1234, 0x0064}, {0x1237, 0x0096}, {0x1238, 0x0078}, {0x1239, 0x0084}, {0x123A, 0x0030}, {0x205F, 0x0002}, {0x2059, 0x1A00}, @@ -730,39 +550,28 @@ static int rtl8367b_write_phy_reg(struct rtl8366_smi *smi, static int rtl8367b_init_regs(struct rtl8366_smi *smi) { const struct rtl8367b_initval *initvals; - u32 chip_num; - u32 chip_ver; - u32 rlvid; int count; - int err; - REG_WR(smi, RTL8367B_RTL_MAGIC_ID_REG, RTL8367B_RTL_MAGIC_ID_VAL); - REG_RD(smi, RTL8367B_CHIP_NUMBER_REG, &chip_num); - REG_RD(smi, RTL8367B_CHIP_VER_REG, &chip_ver); - - if ((chip_ver == 0x0020 || chip_ver == 0x00A0) && chip_num == 0x6367) { + switch (smi->rtl8367b_chip) { + case RTL8367B_CHIP_RTL8367RB: + case RTL8367B_CHIP_RTL8367R_VB: + initvals = rtl8367b_initvals; + count = ARRAY_SIZE(rtl8367b_initvals); + break; + case RTL8367B_CHIP_RTL8367RB_VB: + case RTL8367B_CHIP_RTL8367S: + case RTL8367B_CHIP_RTL8367S_VB: initvals = rtl8367c_initvals; count = ARRAY_SIZE(rtl8367c_initvals); - } else { - rlvid = (chip_ver >> RTL8367B_CHIP_VER_RLVID_SHIFT) & - RTL8367B_CHIP_VER_RLVID_MASK; - switch (rlvid) { - case 0: - initvals = rtl8367r_vb_initvals_0; - count = ARRAY_SIZE(rtl8367r_vb_initvals_0); - break; - case 1: - initvals = rtl8367r_vb_initvals_1; - count = ARRAY_SIZE(rtl8367r_vb_initvals_1); - break; - default: - dev_err(smi->parent, "unknow rlvid %u\n", rlvid); - return -ENODEV; + if ((smi->rtl8367b_chip == RTL8367B_CHIP_RTL8367S_VB) && (smi->emu_vlanmc == NULL)) { + smi->emu_vlanmc = kzalloc(sizeof(struct rtl8366_vlan_mc) * smi->num_vlan_mc, GFP_KERNEL); + dev_info(smi->parent, "alloc vlan mc emulator"); } + break; + default: + return -ENODEV; } - /* TODO: disable RLTP */ - return rtl8367b_write_initvals(smi, initvals, count); } @@ -795,6 +604,7 @@ static int rtl8367b_extif_set_mode(struct rtl8366_smi *smi, int id, enum rtl8367_extif_mode mode) { int err; + u32 data; /* set port mode */ switch (mode) { @@ -814,6 +624,15 @@ static int rtl8367b_extif_set_mode(struct rtl8366_smi *smi, int id, RTL8367B_DEBUG1_DP_MASK(id), (7 << RTL8367B_DEBUG1_DN_SHIFT(id)) | (7 << RTL8367B_DEBUG1_DP_SHIFT(id))); + if ((smi->rtl8367b_chip == RTL8367B_CHIP_RTL8367S_VB) && (id == 1)) { + REG_RMW(smi, RTL8367D_REG_EXT_TXC_DLY, RTL8367D_EXT1_RGMII_TX_DLY_MASK, 0); + /* Configure RGMII/MII mux to port 7 if UTP_PORT4 is not RGMII mode */ + REG_RD(smi, RTL8367D_REG_TOP_CON0, &data); + data &= RTL8367D_MAC4_SEL_EXT1_MASK; + if (data == 0) + REG_RMW(smi, RTL8367D_REG_TOP_CON0, RTL8367D_MAC7_SEL_EXT1_MASK, RTL8367D_MAC7_SEL_EXT1_MASK); + REG_RMW(smi, RTL8367D_REG_SDS1_MISC0, RTL8367D_SDS1_MODE_MASK, RTL8367D_PORT_SDS_MODE_DISABLE); + } } else { REG_RMW(smi, RTL8367B_CHIP_DEBUG2_REG, RTL8367B_DEBUG2_DRI_EXT2 | @@ -872,23 +691,31 @@ static int rtl8367b_extif_set_force(struct rtl8366_smi *smi, int id, u32 val; int err; - mask = (RTL8367B_DI_FORCE_MODE | - RTL8367B_DI_FORCE_NWAY | - RTL8367B_DI_FORCE_TXPAUSE | - RTL8367B_DI_FORCE_RXPAUSE | - RTL8367B_DI_FORCE_LINK | - RTL8367B_DI_FORCE_DUPLEX | - RTL8367B_DI_FORCE_SPEED_MASK); - - val = pa->speed; - val |= pa->force_mode ? RTL8367B_DI_FORCE_MODE : 0; + val = pa->speed & RTL8367B_DI_FORCE_SPEED_MASK; val |= pa->nway ? RTL8367B_DI_FORCE_NWAY : 0; val |= pa->txpause ? RTL8367B_DI_FORCE_TXPAUSE : 0; val |= pa->rxpause ? RTL8367B_DI_FORCE_RXPAUSE : 0; val |= pa->link ? RTL8367B_DI_FORCE_LINK : 0; val |= pa->duplex ? RTL8367B_DI_FORCE_DUPLEX : 0; - REG_RMW(smi, RTL8367B_DI_FORCE_REG(id), mask, val); + if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) { /* Family D */ + val |= (pa->speed << RTL8367D_PORT_STATUS_SPEED1_SHIFT) & RTL8367D_PORT_STATUS_SPEED1_MASK; + if (smi->cpu_port != UINT_MAX) { + REG_WR(smi, RTL8367D_REG_MAC0_FORCE_SELECT + smi->cpu_port, val); + REG_WR(smi, RTL8367D_REG_MAC0_FORCE_SELECT_EN + smi->cpu_port, pa->force_mode ? 0xffff : 0x0000); + } + } else { + val |= pa->force_mode ? RTL8367B_DI_FORCE_MODE : 0; + mask = (RTL8367B_DI_FORCE_MODE | + RTL8367B_DI_FORCE_NWAY | + RTL8367B_DI_FORCE_TXPAUSE | + RTL8367B_DI_FORCE_RXPAUSE | + RTL8367B_DI_FORCE_LINK | + RTL8367B_DI_FORCE_DUPLEX | + RTL8367B_DI_FORCE_SPEED_MASK); + + REG_RMW(smi, RTL8367B_DI_FORCE_REG(id), mask, val); + } return 0; } @@ -939,21 +766,56 @@ static int rtl8367b_extif_init(struct rtl8366_smi *smi, int id, } #ifdef CONFIG_OF -static int rtl8367b_extif_init_of(struct rtl8366_smi *smi, int id, +static int rtl8367b_extif_init_of(struct rtl8366_smi *smi, const char *name) { struct rtl8367_extif_config *cfg; const __be32 *prop; int size; int err; + unsigned cpu_port; + unsigned id = UINT_MAX; prop = of_get_property(smi->parent->of_node, name, &size); - if (!prop) - return rtl8367b_extif_init(smi, id, NULL); + if (!prop || (size != (10 * sizeof(*prop)))) { + dev_err(smi->parent, "%s property is not defined or invalid\n", name); + err = -EINVAL; + goto err_init; + } - if (size != (9 * sizeof(*prop))) { - dev_err(smi->parent, "%s property is invalid\n", name); - return -EINVAL; + cpu_port = be32_to_cpup(prop++); + switch (cpu_port) { + case RTL8367B_CPU_PORT_NUM: + case RTL8367B_CPU_PORT_NUM + 1: + case RTL8367B_CPU_PORT_NUM + 2: + if (smi->rtl8367b_chip == RTL8367B_CHIP_RTL8367R_VB) { /* for the RTL8367R-VB chip, cpu_port 5 corresponds to extif1 */ + if (cpu_port == RTL8367B_CPU_PORT_NUM) + id = 1; + else { + dev_err(smi->parent, "wrong cpu_port %u in %s property\n", cpu_port, name); + err = -EINVAL; + goto err_init; + } + } else if (smi->rtl8367b_chip == RTL8367B_CHIP_RTL8367S_VB) { /* for the RTL8367S-VB chip, cpu_port 7 corresponds to extif1, cpu_port 6 corresponds to extif0 */ + if (cpu_port != RTL8367B_CPU_PORT_NUM) { + id = cpu_port - RTL8367B_CPU_PORT_NUM - 1; + } else { + dev_err(smi->parent, "wrong cpu_port %u in %s property\n", cpu_port, name); + err = -EINVAL; + goto err_init; + } + } else { + id = cpu_port - RTL8367B_CPU_PORT_NUM; + } + if (smi->cpu_port == UINT_MAX) { + dev_info(smi->parent, "cpu_port:%u, assigned to extif%u\n", cpu_port, id); + smi->cpu_port = cpu_port; + } + break; + default: + dev_err(smi->parent, "wrong cpu_port %u in %s property\n", cpu_port, name); + err = -EINVAL; + goto err_init; } cfg = kzalloc(sizeof(struct rtl8367_extif_config), GFP_KERNEL); @@ -973,10 +835,15 @@ static int rtl8367b_extif_init_of(struct rtl8366_smi *smi, int id, err = rtl8367b_extif_init(smi, id, cfg); kfree(cfg); +err_init: + if (id != 0) rtl8367b_extif_init(smi, 0, NULL); + if (id != 1) rtl8367b_extif_init(smi, 1, NULL); + if (id != 2) rtl8367b_extif_init(smi, 2, NULL); + return err; } #else -static int rtl8367b_extif_init_of(struct rtl8366_smi *smi, int id, +static int rtl8367b_extif_init_of(struct rtl8366_smi *smi, const char *name) { return -EINVAL; @@ -997,15 +864,7 @@ static int rtl8367b_setup(struct rtl8366_smi *smi) /* initialize external interfaces */ if (smi->parent->of_node) { - err = rtl8367b_extif_init_of(smi, 0, "realtek,extif0"); - if (err) - return err; - - err = rtl8367b_extif_init_of(smi, 1, "realtek,extif1"); - if (err) - return err; - - err = rtl8367b_extif_init_of(smi, 2, "realtek,extif2"); + err = rtl8367b_extif_init_of(smi, "realtek,extif"); if (err) return err; } else { @@ -1115,8 +974,12 @@ static int rtl8367b_get_vlan_4k(struct rtl8366_smi *smi, u32 vid, RTL8367B_TA_VLAN0_MEMBER_MASK; vlan4k->untag = (data[0] >> RTL8367B_TA_VLAN0_UNTAG_SHIFT) & RTL8367B_TA_VLAN0_UNTAG_MASK; - vlan4k->fid = (data[1] >> RTL8367B_TA_VLAN1_FID_SHIFT) & - RTL8367B_TA_VLAN1_FID_MASK; + if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) /* Family D */ + vlan4k->fid = (data[1] >> RTL8367D_TA_VLAN1_FID_SHIFT) & + RTL8367D_TA_VLAN1_FID_MASK; + else + vlan4k->fid = (data[1] >> RTL8367B_TA_VLAN1_FID_SHIFT) & + RTL8367B_TA_VLAN1_FID_MASK; return 0; } @@ -1131,7 +994,7 @@ static int rtl8367b_set_vlan_4k(struct rtl8366_smi *smi, if (vlan4k->vid >= RTL8367B_NUM_VIDS || vlan4k->member > RTL8367B_TA_VLAN0_MEMBER_MASK || vlan4k->untag > RTL8367B_UNTAG_MASK || - vlan4k->fid > RTL8367B_FIDMAX) + vlan4k->fid > ((smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) ? RTL8367D_FIDMAX : RTL8367B_FIDMAX)) return -EINVAL; memset(data, 0, sizeof(data)); @@ -1140,15 +1003,24 @@ static int rtl8367b_set_vlan_4k(struct rtl8366_smi *smi, RTL8367B_TA_VLAN0_MEMBER_SHIFT; data[0] |= (vlan4k->untag & RTL8367B_TA_VLAN0_UNTAG_MASK) << RTL8367B_TA_VLAN0_UNTAG_SHIFT; - data[1] = (vlan4k->fid & RTL8367B_TA_VLAN1_FID_MASK) << - RTL8367B_TA_VLAN1_FID_SHIFT; + + if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) /* Family D */ + data[1] = ((vlan4k->fid & RTL8367D_TA_VLAN1_FID_MASK) << + RTL8367D_TA_VLAN1_FID_SHIFT) | 12; /* ivl_svl - BIT(3), svlan_chek_ivl_svl - BIT(2) */ + else + data[1] = (vlan4k->fid & RTL8367B_TA_VLAN1_FID_MASK) << + RTL8367B_TA_VLAN1_FID_SHIFT; for (i = 0; i < ARRAY_SIZE(data); i++) REG_WR(smi, RTL8367B_TA_WRDATA_REG(i), data[i]); /* write VID */ - REG_WR(smi, RTL8367B_TA_ADDR_REG, - vlan4k->vid & RTL8367B_TA_VLAN_VID_MASK); + if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) /* Family D */ + REG_WR(smi, RTL8367B_TA_ADDR_REG, + vlan4k->vid & RTL8367D_TA_VLAN_VID_MASK); + else + REG_WR(smi, RTL8367B_TA_ADDR_REG, + vlan4k->vid & RTL8367B_TA_VLAN_VID_MASK); /* write table access control word */ REG_WR(smi, RTL8367B_TA_CTRL_REG, RTL8367B_TA_CTRL_CVLAN_WRITE); @@ -1168,6 +1040,14 @@ static int rtl8367b_get_vlan_mc(struct rtl8366_smi *smi, u32 index, if (index >= RTL8367B_NUM_VLANS) return -EINVAL; + if (smi->emu_vlanmc) { /* use vlan mc emulation */ + vlanmc->vid = smi->emu_vlanmc[index].vid; + vlanmc->member = smi->emu_vlanmc[index].member; + vlanmc->fid = smi->emu_vlanmc[index].fid; + vlanmc->untag = smi->emu_vlanmc[index].untag; + return 0; + } + for (i = 0; i < ARRAY_SIZE(data); i++) REG_RD(smi, RTL8367B_VLAN_MC_BASE(index) + i, &data[i]); @@ -1193,9 +1073,17 @@ static int rtl8367b_set_vlan_mc(struct rtl8366_smi *smi, u32 index, vlanmc->priority > RTL8367B_PRIORITYMAX || vlanmc->member > RTL8367B_VLAN_MC0_MEMBER_MASK || vlanmc->untag > RTL8367B_UNTAG_MASK || - vlanmc->fid > RTL8367B_FIDMAX) + vlanmc->fid > ((smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) ? RTL8367D_FIDMAX : RTL8367B_FIDMAX)) return -EINVAL; + if (smi->emu_vlanmc) { /* use vlanmc emulation */ + smi->emu_vlanmc[index].vid = vlanmc->vid; + smi->emu_vlanmc[index].member = vlanmc->member; + smi->emu_vlanmc[index].fid = vlanmc->fid; + smi->emu_vlanmc[index].untag = vlanmc->untag; + return 0; + } + data[0] = (vlanmc->member & RTL8367B_VLAN_MC0_MEMBER_MASK) << RTL8367B_VLAN_MC0_MEMBER_SHIFT; data[1] = (vlanmc->fid & RTL8367B_VLAN_MC1_FID_MASK) << @@ -1218,10 +1106,41 @@ static int rtl8367b_get_mc_index(struct rtl8366_smi *smi, int port, int *val) if (port >= RTL8367B_NUM_PORTS) return -EINVAL; - REG_RD(smi, RTL8367B_VLAN_PVID_CTRL_REG(port), &data); + if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) { /* Family D */ + int i; + struct rtl8366_vlan_mc vlanmc; - *val = (data >> RTL8367B_VLAN_PVID_CTRL_SHIFT(port)) & - RTL8367B_VLAN_PVID_CTRL_MASK; + err = rtl8366_smi_read_reg(smi, RTL8367D_VLAN_PVID_CTRL_REG(port), &data); + + if (err) { + dev_err(smi->parent, "read pvid register 0x%04x fail", RTL8367D_VLAN_PVID_CTRL_REG(port)); + return err; + } + + data &= RTL8367D_VLAN_PVID_CTRL_MASK; + for (i = 0; i < smi->num_vlan_mc; i++) { + err = rtl8367b_get_vlan_mc(smi, i, &vlanmc); + + if (err) { + dev_err(smi->parent, "get vlan mc index %d fail", i); + return err; + } + + if (data == vlanmc.vid) break; + } + + if (i < smi->num_vlan_mc) { + *val = i; + } else { + dev_err(smi->parent, "vlan mc index for pvid %d not found", data); + return -EINVAL; + } + } else { + REG_RD(smi, RTL8367B_VLAN_PVID_CTRL_REG(port), &data); + + *val = (data >> RTL8367B_VLAN_PVID_CTRL_SHIFT(port)) & + RTL8367B_VLAN_PVID_CTRL_MASK; + } return 0; } @@ -1231,7 +1150,28 @@ static int rtl8367b_set_mc_index(struct rtl8366_smi *smi, int port, int index) if (port >= RTL8367B_NUM_PORTS || index >= RTL8367B_NUM_VLANS) return -EINVAL; - return rtl8366_smi_rmwr(smi, RTL8367B_VLAN_PVID_CTRL_REG(port), + if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) { /* Family D */ + int pvid, err; + struct rtl8366_vlan_mc vlanmc; + + err = rtl8367b_get_vlan_mc(smi, index, &vlanmc); + + if (err) { + dev_err(smi->parent, "get vlan mc index %d fail", index); + return err; + } + + pvid = vlanmc.vid & RTL8367D_VLAN_PVID_CTRL_MASK; + err = rtl8366_smi_write_reg(smi, RTL8367D_VLAN_PVID_CTRL_REG(port), pvid); + + if (err) { + dev_err(smi->parent, "set port %d pvid %d fail", port, pvid); + return err; + } + + return 0; + } else + return rtl8366_smi_rmwr(smi, RTL8367B_VLAN_PVID_CTRL_REG(port), RTL8367B_VLAN_PVID_CTRL_MASK << RTL8367B_VLAN_PVID_CTRL_SHIFT(port), (index & RTL8367B_VLAN_PVID_CTRL_MASK) << @@ -1294,7 +1234,10 @@ static int rtl8367b_sw_get_port_link(struct switch_dev *dev, if (port >= RTL8367B_NUM_PORTS) return -EINVAL; - rtl8366_smi_read_reg(smi, RTL8367B_PORT_STATUS_REG(port), &data); + if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) /* Family D */ + rtl8366_smi_read_reg(smi, RTL8367D_PORT_STATUS_REG(port), &data); + else + rtl8366_smi_read_reg(smi, RTL8367B_PORT_STATUS_REG(port), &data); link->link = !!(data & RTL8367B_PORT_STATUS_LINK); if (!link->link) @@ -1305,15 +1248,18 @@ static int rtl8367b_sw_get_port_link(struct switch_dev *dev, link->tx_flow = !!(data & RTL8367B_PORT_STATUS_TXPAUSE); link->aneg = !!(data & RTL8367B_PORT_STATUS_NWAY); - speed = (data & RTL8367B_PORT_STATUS_SPEED_MASK); + if (smi->rtl8367b_chip >= RTL8367B_CHIP_RTL8367S_VB) /* Family D */ + speed = (data & RTL8367B_PORT_STATUS_SPEED_MASK) | ((data & RTL8367D_PORT_STATUS_SPEED1_MASK) >> RTL8367D_PORT_STATUS_SPEED1_SHIFT); + else + speed = (data & RTL8367B_PORT_STATUS_SPEED_MASK); switch (speed) { - case 0: + case RTL8367B_PORT_STATUS_SPEED_10: link->speed = SWITCH_PORT_SPEED_10; break; - case 1: + case RTL8367B_PORT_STATUS_SPEED_100: link->speed = SWITCH_PORT_SPEED_100; break; - case 2: + case RTL8367B_PORT_STATUS_SPEED_1000: link->speed = SWITCH_PORT_SPEED_1000; break; default: @@ -1530,10 +1476,11 @@ static int rtl8367b_detect(struct rtl8366_smi *smi) const char *chip_name = NULL; u32 chip_num; u32 chip_ver; - u32 chip_mode; int ret; - /* TODO: improve chip detection */ + smi->emu_vlanmc = NULL; + smi->rtl8367b_chip = RTL8367B_CHIP_UNKNOWN; + rtl8366_smi_write_reg(smi, RTL8367B_RTL_MAGIC_ID_REG, RTL8367B_RTL_MAGIC_ID_VAL); @@ -1551,44 +1498,42 @@ static int rtl8367b_detect(struct rtl8366_smi *smi) return ret; } - ret = rtl8366_smi_read_reg(smi, RTL8367B_CHIP_MODE_REG, &chip_mode); - if (ret) { - dev_err(smi->parent, "unable to read %s register\n", - "chip mode"); - return ret; - } - switch (chip_ver) { + case 0x0010: + if (chip_num == 0x6642) { + chip_name = "8367S-VB"; + smi->rtl8367b_chip = RTL8367B_CHIP_RTL8367S_VB; + } + break; case 0x0020: - if (chip_num == 0x6367) + if (chip_num == 0x6367) { chip_name = "8367RB-VB"; + smi->rtl8367b_chip = RTL8367B_CHIP_RTL8367RB_VB; + } break; case 0x00A0: - if (chip_num == 0x6367) + if (chip_num == 0x6367) { chip_name = "8367S"; + smi->rtl8367b_chip = RTL8367B_CHIP_RTL8367S; + } break; case 0x1000: chip_name = "8367RB"; + smi->rtl8367b_chip = RTL8367B_CHIP_RTL8367RB; break; case 0x1010: chip_name = "8367R-VB"; + smi->rtl8367b_chip = RTL8367B_CHIP_RTL8367R_VB; } if (!chip_name) { dev_err(smi->parent, - "unknown chip num:%04x ver:%04x, mode:%04x\n", - chip_num, chip_ver, chip_mode); + "unknown chip (num:%04x ver:%04x)\n", + chip_num, chip_ver); return -ENODEV; } - dev_info(smi->parent, "RTL%s chip found\n", chip_name); - - if (of_property_present(smi->parent->of_node, "realtek,extif2")) - smi->cpu_port = RTL8367B_CPU_PORT_NUM + 2; - else if (of_property_present(smi->parent->of_node, "realtek,extif1") && (chip_ver != 0x1010)) /* for the RTL8367R-VB chip, extif1 corresponds to cpu_port 5 */ - smi->cpu_port = RTL8367B_CPU_PORT_NUM + 1; - - dev_info(smi->parent, "CPU port: %u\n", smi->cpu_port); + dev_info(smi->parent, "RTL%s chip found (num:%04x ver:%04x)\n", chip_name, chip_num, chip_ver); return 0; } @@ -1628,7 +1573,7 @@ static int rtl8367b_probe(struct platform_device *pdev) smi->cmd_write = 0xb8; smi->ops = &rtl8367b_smi_ops; smi->num_ports = RTL8367B_NUM_PORTS; - smi->cpu_port = RTL8367B_CPU_PORT_NUM; + smi->cpu_port = UINT_MAX; /* not defined yet */ smi->num_vlan_mc = RTL8367B_NUM_VLANS; smi->mib_counters = rtl8367b_mib_counters; smi->num_mib_counters = ARRAY_SIZE(rtl8367b_mib_counters); @@ -1649,6 +1594,8 @@ static int rtl8367b_probe(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); rtl8366_smi_cleanup(smi); err_free_smi: + if (smi->emu_vlanmc) + kfree(smi->emu_vlanmc); kfree(smi); return err; } @@ -1686,7 +1633,6 @@ MODULE_DEVICE_TABLE(of, rtl8367b_match); static struct platform_driver rtl8367b_driver = { .driver = { .name = RTL8367B_DRIVER_NAME, - .owner = THIS_MODULE, #ifdef CONFIG_OF .of_match_table = of_match_ptr(rtl8367b_match), #endif diff --git a/target/linux/generic/files/drivers/net/phy/swconfig.c b/target/linux/generic/files/drivers/net/phy/swconfig.c index 5fa2b147c6..10dc8d0607 100644 --- a/target/linux/generic/files/drivers/net/phy/swconfig.c +++ b/target/linux/generic/files/drivers/net/phy/swconfig.c @@ -24,7 +24,6 @@ #include <linux/skbuff.h> #include <linux/switch.h> #include <linux/of.h> -#include <linux/version.h> #include <uapi/linux/mii.h> #define SWCONFIG_DEVNAME "switch%d" @@ -1054,9 +1053,7 @@ static struct genl_family switch_fam = { .module = THIS_MODULE, .ops = swconfig_ops, .n_ops = ARRAY_SIZE(swconfig_ops), -#if LINUX_VERSION_CODE > KERNEL_VERSION(6,0,0) .resv_start_op = SWITCH_CMD_SET_VLAN + 1, -#endif }; #ifdef CONFIG_OF diff --git a/target/linux/generic/files/drivers/net/phy/swconfig_leds.c b/target/linux/generic/files/drivers/net/phy/swconfig_leds.c index 1d309c046c..1fcd4432b5 100644 --- a/target/linux/generic/files/drivers/net/phy/swconfig_leds.c +++ b/target/linux/generic/files/drivers/net/phy/swconfig_leds.c @@ -85,11 +85,7 @@ swconfig_trig_update_port_mask(struct led_trigger *trigger) sw_trig = (void *) trigger; port_mask = 0; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,16,0) spin_lock(&trigger->leddev_list_lock); -#else - read_lock(&trigger->leddev_list_lock); -#endif list_for_each(entry, &trigger->led_cdevs) { struct led_classdev *led_cdev; struct swconfig_trig_data *trig_data; @@ -102,11 +98,7 @@ swconfig_trig_update_port_mask(struct led_trigger *trigger) read_unlock(&trig_data->lock); } } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,16,0) spin_unlock(&trigger->leddev_list_lock); -#else - read_unlock(&trigger->leddev_list_lock); -#endif sw_trig->port_mask = port_mask; @@ -426,22 +418,14 @@ swconfig_trig_update_leds(struct switch_led_trigger *sw_trig) struct led_trigger *trigger; trigger = &sw_trig->trig; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,16,0) spin_lock(&trigger->leddev_list_lock); -#else - read_lock(&trigger->leddev_list_lock); -#endif list_for_each(entry, &trigger->led_cdevs) { struct led_classdev *led_cdev; led_cdev = list_entry(entry, struct led_classdev, trig_list); swconfig_trig_led_event(sw_trig, led_cdev); } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,16,0) spin_unlock(&trigger->leddev_list_lock); -#else - read_unlock(&trigger->leddev_list_lock); -#endif } static void diff --git a/target/linux/generic/files/drivers/platform/mikrotik/Kconfig b/target/linux/generic/files/drivers/platform/mikrotik/Kconfig index 32ef8f29de..85fe7b2050 100644 --- a/target/linux/generic/files/drivers/platform/mikrotik/Kconfig +++ b/target/linux/generic/files/drivers/platform/mikrotik/Kconfig @@ -21,4 +21,11 @@ config NVMEM_LAYOUT_MIKROTIK help This driver exposes MikroTik hard_config via NVMEM layout. +config MIKROTIK_WLAN_DECOMPRESS_LZ77 + tristate "Mikrotik factory Wi-Fi caldata LZ77 decompression support" + depends on MIKROTIK_RB_SYSFS + help + Allow Mikrotik LZ77 factory flashed Wi-Fi calibration data to be + decompressed + endif # MIKROTIK diff --git a/target/linux/generic/files/drivers/platform/mikrotik/Makefile b/target/linux/generic/files/drivers/platform/mikrotik/Makefile index 164b23b701..9ffb355c1e 100644 --- a/target/linux/generic/files/drivers/platform/mikrotik/Makefile +++ b/target/linux/generic/files/drivers/platform/mikrotik/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_MIKROTIK_RB_SYSFS) += routerboot.o rb_hardconfig.o rb_softconfig.o obj-$(CONFIG_NVMEM_LAYOUT_MIKROTIK) += rb_nvmem.o +obj-$(CONFIG_MIKROTIK_WLAN_DECOMPRESS_LZ77) += rb_lz77.o diff --git a/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c b/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c index 78e39a7f94..4c1edad081 100644 --- a/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c +++ b/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c @@ -39,8 +39,9 @@ #include "rb_hardconfig.h" #include "routerboot.h" +#include "rb_lz77.h" -#define RB_HARDCONFIG_VER "0.07" +#define RB_HARDCONFIG_VER "0.08" #define RB_HC_PR_PFX "[rb_hardconfig] " /* Bit definitions for hardware options */ @@ -465,23 +466,24 @@ fail: /* * If the RB_ID_WLAN_DATA payload starts with RB_MAGIC_LZOR, then past * that magic number is a payload that must be appended to the hc_lzor_prefix, - * the resulting blob is LZO-compressed. In the LZO decompression result, + * the resulting blob is LZO-compressed. + * If payload starts with RB_MAGIC_LZ77, a separate (bit level LZ77) + * decompression function needs to be used. In the decompressed result, * the RB_MAGIC_ERD magic number (aligned) must be located. Following that * magic, there is one or more routerboot tag node(s) locating the RLE-encoded * calibration data payload. */ -static int hc_wlan_data_unpack_lzor(const u16 tag_id, const u8 *inbuf, size_t inlen, - void *outbuf, size_t *outlen) +static int hc_wlan_data_unpack_lzor_lz77(const u16 tag_id, const u8 *inbuf, size_t inlen, + void *outbuf, size_t *outlen, u32 magic) { u16 rle_ofs, rle_len; const u32 *needle; u8 *tempbuf; size_t templen, lzo_len; int ret; - - lzo_len = inlen + sizeof(hc_lzor_prefix); - if (lzo_len > *outlen) - return -EFBIG; + const char lzor[] = "LZOR"; + const char lz77[] = "LZ77"; + const char *lz_type; /* Temporary buffer same size as the outbuf */ templen = *outlen; @@ -489,23 +491,50 @@ static int hc_wlan_data_unpack_lzor(const u16 tag_id, const u8 *inbuf, size_t in if (!tempbuf) return -ENOMEM; - /* Concatenate into the outbuf */ - memcpy(outbuf, hc_lzor_prefix, sizeof(hc_lzor_prefix)); - memcpy(outbuf + sizeof(hc_lzor_prefix), inbuf, inlen); + lzo_len = inlen; + if (magic == RB_MAGIC_LZOR) + lzo_len += sizeof(hc_lzor_prefix); + if (lzo_len > *outlen) + return -EFBIG; - /* LZO-decompress lzo_len bytes of outbuf into the tempbuf */ - ret = lzo1x_decompress_safe(outbuf, lzo_len, tempbuf, &templen); - if (ret) { - if (LZO_E_INPUT_NOT_CONSUMED == ret) { - /* - * The tag length is always aligned thus the LZO payload may be padded, - * which can trigger a spurious error which we ignore here. - */ - pr_debug(RB_HC_PR_PFX "LZOR: LZO EOF before buffer end - this may be harmless\n"); - } else { - pr_debug(RB_HC_PR_PFX "LZOR: LZO decompression error (%d)\n", ret); + switch (magic) { + case RB_MAGIC_LZOR: + lz_type = lzor; + + /* Concatenate into the outbuf */ + memcpy(outbuf, hc_lzor_prefix, sizeof(hc_lzor_prefix)); + memcpy(outbuf + sizeof(hc_lzor_prefix), inbuf, inlen); + + /* LZO-decompress lzo_len bytes of outbuf into the tempbuf */ + ret = lzo1x_decompress_safe(outbuf, lzo_len, tempbuf, &templen); + if (ret) { + if (LZO_E_INPUT_NOT_CONSUMED == ret) { + /* + * The tag length is always aligned thus the LZO payload may be padded, + * which can trigger a spurious error which we ignore here. + */ + pr_debug(RB_HC_PR_PFX "LZOR: LZO EOF before buffer end - this may be harmless\n"); + } else { + pr_debug(RB_HC_PR_PFX "LZOR: LZO decompression error (%d)\n", ret); + goto fail; + } + } + break; + case RB_MAGIC_LZ77: + lz_type = lz77; + /* LZO-decompress lzo_len bytes of inbuf into the tempbuf */ + ret = rb_lz77_decompress(inbuf, inlen, tempbuf, &templen); + if (ret) { + pr_err(RB_HC_PR_PFX "LZ77: LZ77 decompress error %d\n", ret); goto fail; } + + pr_debug(RB_HC_PR_PFX "LZ77: decompressed from %zu to %zu\n", + inlen, templen); + break; + default: + return -EINVAL; + break; } /* @@ -516,7 +545,7 @@ static int hc_wlan_data_unpack_lzor(const u16 tag_id, const u8 *inbuf, size_t in needle = (const u32 *)tempbuf; while (RB_MAGIC_ERD != *needle++) { if ((u8 *)needle >= tempbuf+templen) { - pr_debug(RB_HC_PR_PFX "LZOR: ERD magic not found\n"); + pr_warn(RB_HC_PR_PFX "%s: ERD magic not found. Decompressed first word: 0x%08x\n", lz_type, *(u32 *)tempbuf); ret = -ENODATA; goto fail; } @@ -526,12 +555,12 @@ static int hc_wlan_data_unpack_lzor(const u16 tag_id, const u8 *inbuf, size_t in /* Past magic. Look for tag node */ ret = routerboot_tag_find((u8 *)needle, templen, tag_id, &rle_ofs, &rle_len); if (ret) { - pr_debug(RB_HC_PR_PFX "LZOR: no RLE data for id 0x%04x\n", tag_id); + pr_debug(RB_HC_PR_PFX "%s: no RLE data for id 0x%04x\n", lz_type, tag_id); goto fail; } if (rle_len > templen) { - pr_debug(RB_HC_PR_PFX "LZOR: Invalid RLE data length\n"); + pr_debug(RB_HC_PR_PFX "%s: Invalid RLE data length\n", lz_type); ret = -EINVAL; goto fail; } @@ -539,7 +568,7 @@ static int hc_wlan_data_unpack_lzor(const u16 tag_id, const u8 *inbuf, size_t in /* RLE-decode tempbuf from needle back into the outbuf */ ret = routerboot_rle_decode((u8 *)needle+rle_ofs, rle_len, outbuf, outlen); if (ret) - pr_debug(RB_HC_PR_PFX "LZOR: RLE decoding error (%d)\n", ret); + pr_debug(RB_HC_PR_PFX "%s: RLE decoding error (%d)\n", lz_type, ret); fail: kfree(tempbuf); @@ -562,11 +591,18 @@ static int hc_wlan_data_unpack(const u16 tag_id, const size_t tofs, size_t tlen, ret = -ENODATA; switch (magic) { + case RB_MAGIC_LZ77: + /* no known instances of lz77 without 8001/8201 data, skip SOLO */ + if (tag_id == RB_WLAN_ERD_ID_SOLO) { + pr_debug(RB_HC_PR_PFX "skipped LZ77 decompress in search for SOLO tag\n"); + break; + } + fallthrough; case RB_MAGIC_LZOR: /* Skip magic */ lbuf += sizeof(magic); tlen -= sizeof(magic); - ret = hc_wlan_data_unpack_lzor(tag_id, lbuf, tlen, outbuf, outlen); + ret = hc_wlan_data_unpack_lzor_lz77(tag_id, lbuf, tlen, outbuf, outlen, magic); break; case RB_MAGIC_ERD: /* Skip magic */ diff --git a/target/linux/generic/files/drivers/platform/mikrotik/rb_lz77.c b/target/linux/generic/files/drivers/platform/mikrotik/rb_lz77.c new file mode 100644 index 0000000000..d443adb128 --- /dev/null +++ b/target/linux/generic/files/drivers/platform/mikrotik/rb_lz77.c @@ -0,0 +1,446 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 John Thomson + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/minmax.h> + +#include "rb_lz77.h" + +#define MIKRO_LZ77 "[rb lz77] " + +/* + * The maximum number of bits used in a counter. + * For the look behind window, long instruction match offsets + * up to 6449 have been seen in provided compressed caldata blobs + * (that would need 21 counter bits: 4 to 12 + 11 to 0). + * conservative value here: 27 provides offset up to 0x8000 bytes + * uses a u8 in this code + */ +#define MIKRO_LZ77_MAX_COUNT_BIT_LEN 27 + +enum rb_lz77_instruction { + INSTR_ERROR = -1, + INSTR_LITERAL_BYTE = 0, + /* a (non aligned) byte follows this instruction, + * which is directly copied into output + */ + INSTR_PREVIOUS_OFFSET = 1, + /* this group is a match, with a bytes length defined by + * following counter bits, starting at bitshift 0, + * less the built-in count of 1 + * using the previous offset as source + */ + INSTR_LONG = 2 + /* this group has two counters, + * the first counter starts at bitshift 4, + * if this counter == 0, this is a non-matching group + * the second counter (bytes length) starts at bitshift 4, + * less the built-in count of 11+1. + * The final match group has this count 0, + * and following bits which pad to byte-alignment. + * + * if this counter > 0, this is a matching group + * this first count is the match offset (in bytes) + * the second count is the match length (in bytes), + * less the built-in count of 2 + * these groups can source bytes that are part of this group + */ +}; + +struct rb_lz77_instr_opcodes { + /* group instruction */ + enum rb_lz77_instruction instruction; + /* if >0, a match group, + * which starts at byte output_position - 1*offset + */ + size_t offset; + /* how long the match group is, + * or how long the (following counter) non-match group is + */ + size_t length; + /* how many bits were used for this instruction + op code(s) */ + size_t bits_used; + /* input char */ + u8 *in; + /* offset where this instruction started */ + size_t in_pos; +}; + +/** + * rb_lz77_get_bit + * + * @in: compressed data ptr + * @in_offset_bit: bit offset to extract + * + * convert the bit offset to byte offset, + * shift to modulo of bits per bytes, so that wanted bit is lsb + * and to extract only that bit. + * Caller is responsible for ensuring that in_offset_bit/8 + * does not exceed input length + */ +static inline u8 rb_lz77_get_bit(const u8 *in, const size_t in_offset_bit) +{ + return ((in[in_offset_bit / BITS_PER_BYTE] >> + (in_offset_bit % BITS_PER_BYTE)) & + 1); +} + +/** + * rb_lz77_get_byte + * + * @in: compressed data + * @in_offset_bit: bit offset to extract byte + */ +static inline u8 rb_lz77_get_byte(const u8 *in, const size_t in_offset_bit) +{ + u8 buf = 0; + int i; + + /* built a reversed byte from (likely) unaligned bits */ + for (i = 0; i <= 7; ++i) + buf += rb_lz77_get_bit(in, in_offset_bit + i) << (7 - i); + return buf; +} + +/** + * rb_lz77_decode_count - decode bits at given offset as a count + * + * @in: compressed data + * @in_len: length of compressed data + * @in_offset_bit: bit offset where count starts + * @shift: left shift operand value of first count bit + * @count: initial count + * @bits_used: how many bits were consumed by this count + * @max_bits: maximum bit count for this counter + * + * Returns the decoded count + */ +static int rb_lz77_decode_count(const u8 *in, const size_t in_len, + const size_t in_offset_bit, u8 shift, + size_t count, u8 *bits_used, const u8 max_bits) +{ + size_t pos = in_offset_bit; + const size_t max_pos = min(pos + max_bits, in_len * BITS_PER_BYTE); + bool up = true; + + *bits_used = 0; + pr_debug(MIKRO_LZ77 + "decode_count inbit: %zu, start shift:%u, initial count:%zu\n", + in_offset_bit, shift, count); + + while (true) { + /* check the input offset bit does not overflow the minimum of + * a reasonable length for this encoded count, and + * the end of the input */ + if (unlikely(pos >= max_pos)) { + pr_err(MIKRO_LZ77 + "max bit index reached before count completed\n"); + return -EFBIG; + } + + /* if the bit value at offset is set */ + if (rb_lz77_get_bit(in, pos)) + count += (1 << shift); + + /* shift increases until we find an unsed bit */ + else if (up) + up = false; + + if (up) + ++shift; + else { + if (!shift) { + *bits_used = pos - in_offset_bit + 1; + return count; + } + --shift; + } + + ++pos; + } + + return -EINVAL; +} + +/** + * rb_lz77_decode_instruction + * + * @in: compressed data + * @in_offset_bit: bit offset where instruction starts + * @bits_used: how many bits were consumed by this count + * + * Returns the decoded instruction + */ +static enum rb_lz77_instruction +rb_lz77_decode_instruction(const u8 *in, size_t in_offset_bit, u8 *bits_used) +{ + if (rb_lz77_get_bit(in, in_offset_bit)) { + *bits_used = 2; + if (rb_lz77_get_bit(in, ++in_offset_bit)) + return INSTR_LONG; + else + return INSTR_PREVIOUS_OFFSET; + } else { + *bits_used = 1; + return INSTR_LITERAL_BYTE; + } + return INSTR_ERROR; +} + +/** + * rb_lz77_decode_instruction_operators + * + * @in: compressed data + * @in_len: length of compressed data + * @in_offset_bit: bit offset where instruction starts + * @previous_offset: last used match offset + * @opcode: struct to hold instruction & operators + * + * Returns error code + */ +static int rb_lz77_decode_instruction_operators( + const u8 *in, const size_t in_len, const size_t in_offset_bit, + const size_t previous_offset, struct rb_lz77_instr_opcodes *opcode) +{ + enum rb_lz77_instruction instruction; + u8 bit_count = 0; + u8 bits_used = 0; + int offset = 0; + int length = 0; + + instruction = rb_lz77_decode_instruction(in, in_offset_bit, &bit_count); + + /* skip bits used by instruction */ + bits_used += bit_count; + + switch (instruction) { + case INSTR_LITERAL_BYTE: + /* non-matching char */ + offset = 0; + length = 1; + break; + + case INSTR_PREVIOUS_OFFSET: + /* matching group uses previous offset */ + offset = previous_offset; + + length = rb_lz77_decode_count(in, in_len, + in_offset_bit + bits_used, 0, 1, + &bit_count, + MIKRO_LZ77_MAX_COUNT_BIT_LEN); + if (unlikely(length < 0)) + return length; + /* skip bits used by count */ + bits_used += bit_count; + break; + + case INSTR_LONG: + offset = rb_lz77_decode_count(in, in_len, + in_offset_bit + bits_used, 4, 0, + &bit_count, + MIKRO_LZ77_MAX_COUNT_BIT_LEN); + if (unlikely(offset < 0)) + return offset; + + /* skip bits used by offset count */ + bits_used += bit_count; + + if (offset == 0) { + /* non-matching long group */ + length = rb_lz77_decode_count( + in, in_len, in_offset_bit + bits_used, 4, 12, + &bit_count, MIKRO_LZ77_MAX_COUNT_BIT_LEN); + if (unlikely(length < 0)) + return length; + /* skip bits used by length count */ + bits_used += bit_count; + } else { + /* matching group */ + length = rb_lz77_decode_count( + in, in_len, in_offset_bit + bits_used, 0, 2, + &bit_count, MIKRO_LZ77_MAX_COUNT_BIT_LEN); + if (unlikely(length < 0)) + return length; + /* skip bits used by length count */ + bits_used += bit_count; + } + + break; + + case INSTR_ERROR: + return -EINVAL; + } + + opcode->instruction = instruction; + opcode->offset = offset; + opcode->length = length; + opcode->bits_used = bits_used; + opcode->in = (u8 *)in; + opcode->in_pos = in_offset_bit; + return 0; +} + +/** + * rb_lz77_decompress + * + * @in: compressed data ptr + * @in_len: length of compressed data + * @out: buffer ptr to decompress into + * @out_len: length of decompressed buffer in input, + * length of decompressed data in success + * + * Returns 0 on success, or negative error + */ +int rb_lz77_decompress(const u8 *in, const size_t in_len, u8 *out, + size_t *out_len) +{ + u8 *output_ptr; + size_t input_bit = 0; + const u8 *output_end = out + *out_len; + struct rb_lz77_instr_opcodes *opcode; + size_t match_offset = 0; + int rc = 0; + size_t match_length, partial_count, i; + + output_ptr = out; + + if (unlikely((in_len * BITS_PER_BYTE) > SIZE_MAX)) { + pr_err(MIKRO_LZ77 "input longer than expected\n"); + return -EFBIG; + } + + opcode = kmalloc(sizeof(*opcode), GFP_KERNEL); + if (!opcode) + return -ENOMEM; + + while (true) { + if (unlikely(output_ptr > output_end)) { + pr_err(MIKRO_LZ77 "output overrun\n"); + rc = -EOVERFLOW; + goto free_lz77_struct; + } + if (unlikely(input_bit > in_len * BITS_PER_BYTE)) { + pr_err(MIKRO_LZ77 "input overrun\n"); + rc = -ENODATA; + goto free_lz77_struct; + } + + rc = rb_lz77_decode_instruction_operators(in, in_len, input_bit, + match_offset, opcode); + if (unlikely(rc < 0)) { + pr_err(MIKRO_LZ77 + "instruction operands decode error\n"); + goto free_lz77_struct; + } + + pr_debug(MIKRO_LZ77 "inbit:0x%zx->outbyte:0x%zx", input_bit, + output_ptr - out); + + input_bit += opcode->bits_used; + switch (opcode->instruction) { + case INSTR_LITERAL_BYTE: + pr_debug(" short"); + fallthrough; + case INSTR_LONG: + if (opcode->offset == 0) { + /* this is a non-matching group */ + pr_debug(" non-match, len: 0x%zx\n", + opcode->length); + /* test end marker */ + if (opcode->length == 0xc && + ((input_bit + + opcode->length * BITS_PER_BYTE) > + in_len)) { + *out_len = output_ptr - out; + pr_debug( + MIKRO_LZ77 + "lz77 decompressed from %zu to %zu\n", + in_len, *out_len); + rc = 0; + goto free_lz77_struct; + } + for (i = opcode->length; i > 0; --i) { + *output_ptr = + rb_lz77_get_byte(in, input_bit); + ++output_ptr; + input_bit += BITS_PER_BYTE; + } + /* do no fallthrough if a non-match group */ + break; + } + match_offset = opcode->offset; + fallthrough; + case INSTR_PREVIOUS_OFFSET: + match_length = opcode->length; + partial_count = 0; + + pr_debug(" match, offset: 0x%zx, len: 0x%zx", + opcode->offset, match_length); + + if (unlikely(opcode->offset == 0)) { + pr_err(MIKRO_LZ77 + "match group missing opcode->offset\n"); + rc = -EBADMSG; + goto free_lz77_struct; + } + + /* overflow */ + if (unlikely((output_ptr + match_length) > + output_end)) { + pr_err(MIKRO_LZ77 + "match group output overflow\n"); + rc = -ENOBUFS; + goto free_lz77_struct; + } + + /* underflow */ + if (unlikely((output_ptr - opcode->offset) < out)) { + pr_err(MIKRO_LZ77 + "match group offset underflow\n"); + rc = -ESPIPE; + goto free_lz77_struct; + } + + /* there are cases where the match (length) includes + * data that is a part of the same match + */ + while (opcode->offset < match_length) { + ++partial_count; + memcpy(output_ptr, output_ptr - opcode->offset, + opcode->offset); + output_ptr += opcode->offset; + match_length -= opcode->offset; + } + memcpy(output_ptr, output_ptr - opcode->offset, + match_length); + output_ptr += match_length; + if (partial_count) + pr_debug(" (%zu partial memcpy)", + partial_count); + pr_debug("\n"); + + break; + + case INSTR_ERROR: + rc = -EINVAL; + goto free_lz77_struct; + } + } + + pr_err(MIKRO_LZ77 "decode loop broken\n"); + rc = -EINVAL; + +free_lz77_struct: + kfree(opcode); + return rc; +} +EXPORT_SYMBOL_GPL(rb_lz77_decompress); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Mikrotik Wi-Fi caldata LZ77 decompressor"); +MODULE_AUTHOR("John Thomson"); diff --git a/target/linux/generic/files/drivers/platform/mikrotik/rb_lz77.h b/target/linux/generic/files/drivers/platform/mikrotik/rb_lz77.h new file mode 100644 index 0000000000..55179fcbc8 --- /dev/null +++ b/target/linux/generic/files/drivers/platform/mikrotik/rb_lz77.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2024 John Thomson + */ + +#ifndef __MIKROTIK_WLAN_LZ77_H__ +#define __MIKROTIK_WLAN_LZ77_H__ + +#include <linux/errno.h> + +#ifdef CONFIG_MIKROTIK_WLAN_DECOMPRESS_LZ77 +/** + * rb_lz77_decompress + * + * @in: compressed data ptr + * @in_len: length of compressed data + * @out: buffer ptr to decompress into + * @out_len: length of decompressed buffer in input, + * length of decompressed data in success + * + * Returns 0 on success, or negative error + */ +int rb_lz77_decompress(const u8 *in, const size_t in_len, u8 *out, + size_t *out_len); + +#else /* CONFIG_MIKROTIK_WLAN_DECOMPRESS_LZ77 */ + +static inline int rb_lz77_decompress(const u8 *in, const size_t in_len, u8 *out, + size_t *out_len) +{ + return -EOPNOTSUPP; +} + +#endif /* CONFIG_MIKROTIK_WLAN_DECOMPRESS_LZ77 */ +#endif /* __MIKROTIK_WLAN_LZ77_H__ */ diff --git a/target/linux/generic/files/drivers/platform/mikrotik/routerboot.h b/target/linux/generic/files/drivers/platform/mikrotik/routerboot.h index e858a524af..723f993eeb 100644 --- a/target/linux/generic/files/drivers/platform/mikrotik/routerboot.h +++ b/target/linux/generic/files/drivers/platform/mikrotik/routerboot.h @@ -15,6 +15,7 @@ #define RB_MAGIC_HARD (('H') | ('a' << 8) | ('r' << 16) | ('d' << 24)) #define RB_MAGIC_SOFT (('S') | ('o' << 8) | ('f' << 16) | ('t' << 24)) #define RB_MAGIC_LZOR (('L') | ('Z' << 8) | ('O' << 16) | ('R' << 24)) +#define RB_MAGIC_LZ77 (('L' << 24) | ('Z' << 16) | ('7' << 8) | ('7')) #define RB_MAGIC_ERD (('E' << 16) | ('R' << 8) | ('D')) #define RB_ART_SIZE 0x10000 |