1
0
Fork 0
mirror of https://github.com/Ysurac/openmptcprouter.git synced 2025-03-09 15:40:20 +00:00

Add a directory by kernel instead of a common root, add qnap-301w and rpi4 kernel 6.1 suppport

This commit is contained in:
Ycarus (Yannick Chabanois) 2023-04-22 08:07:24 +02:00
parent e910436a7a
commit 46837ec4c0
9459 changed files with 362648 additions and 116345 deletions

View file

@ -0,0 +1,25 @@
--- a/drivers/mtd/nand/spi/xtx.c
+++ b/drivers/mtd/nand/spi/xtx.c
@@ -37,8 +37,8 @@
if (section)
return -ERANGE;
- region->offset = 8;
- region->length = 40;
+ region->offset = 48;
+ region->length = 16;
return 0;
}
@@ -49,8 +49,9 @@
if (section)
return -ERANGE;
- region->offset = 1;
- region->length = 7;
+ /* Reserve 2 bytes for the BBM. */
+ region->offset = 2;
+ region->length = 62;
return 0;
}

View file

@ -0,0 +1,165 @@
From 4267880319bc1a2270d352e0ded6d6386242a7ef Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Tue, 12 Aug 2014 20:49:27 +0200
Subject: [PATCH 24/53] GPIO: add named gpio exports
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/gpio/gpiolib-of.c | 68 +++++++++++++++++++++++++++++++++++++++++
drivers/gpio/gpiolib-sysfs.c | 10 +++++-
include/asm-generic/gpio.h | 6 ++++
include/linux/gpio/consumer.h | 8 +++++
4 files changed, 91 insertions(+), 1 deletion(-)
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -19,6 +19,8 @@
#include <linux/pinctrl/pinctrl.h>
#include <linux/slab.h>
#include <linux/gpio/machine.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
#include "gpiolib.h"
#include "gpiolib-of.h"
@@ -915,3 +917,68 @@ void of_gpiochip_remove(struct gpio_chip
{
of_node_put(chip->of_node);
}
+
+static struct of_device_id gpio_export_ids[] = {
+ { .compatible = "gpio-export" },
+ { /* sentinel */ }
+};
+
+static int of_gpio_export_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *cnp;
+ u32 val;
+ int nb = 0;
+
+ for_each_child_of_node(np, cnp) {
+ const char *name = NULL;
+ int gpio;
+ bool dmc;
+ int max_gpio = 1;
+ int i;
+
+ of_property_read_string(cnp, "gpio-export,name", &name);
+
+ if (!name)
+ max_gpio = of_gpio_count(cnp);
+
+ for (i = 0; i < max_gpio; i++) {
+ unsigned flags = 0;
+ enum of_gpio_flags of_flags;
+
+ gpio = of_get_gpio_flags(cnp, i, &of_flags);
+ if (!gpio_is_valid(gpio))
+ return gpio;
+
+ if (of_flags == OF_GPIO_ACTIVE_LOW)
+ flags |= GPIOF_ACTIVE_LOW;
+
+ if (!of_property_read_u32(cnp, "gpio-export,output", &val))
+ flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+ else
+ flags |= GPIOF_IN;
+
+ if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np)))
+ continue;
+
+ dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change");
+ gpio_export_with_name(gpio, dmc, name);
+ nb++;
+ }
+ }
+
+ dev_info(&pdev->dev, "%d gpio(s) exported\n", nb);
+
+ return 0;
+}
+
+static struct platform_driver gpio_export_driver = {
+ .driver = {
+ .name = "gpio-export",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(gpio_export_ids),
+ },
+ .probe = of_gpio_export_probe,
+};
+
+module_platform_driver(gpio_export_driver);
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -571,7 +571,7 @@ static struct class gpio_class = {
*
* Returns zero on success, else an error.
*/
-int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
+int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name)
{
struct gpio_chip *chip;
struct gpio_device *gdev;
@@ -633,6 +633,8 @@ int gpiod_export(struct gpio_desc *desc,
offset = gpio_chip_hwgpio(desc);
if (chip->names && chip->names[offset])
ioname = chip->names[offset];
+ if (name)
+ ioname = name;
dev = device_create_with_groups(&gpio_class, &gdev->dev,
MKDEV(0, 0), data, gpio_groups,
@@ -654,6 +656,12 @@ err_unlock:
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
return status;
}
+EXPORT_SYMBOL_GPL(__gpiod_export);
+
+int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
+{
+ return __gpiod_export(desc, direction_may_change, NULL);
+}
EXPORT_SYMBOL_GPL(gpiod_export);
static int match_export(struct device *dev, const void *desc)
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -127,6 +127,12 @@ static inline int gpio_export(unsigned g
return gpiod_export(gpio_to_desc(gpio), direction_may_change);
}
+int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
+static inline int gpio_export_with_name(unsigned gpio, bool direction_may_change, const char *name)
+{
+ return __gpiod_export(gpio_to_desc(gpio), direction_may_change, name);
+}
+
static inline int gpio_export_link(struct device *dev, const char *name,
unsigned gpio)
{
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -668,6 +668,7 @@ static inline void devm_acpi_dev_remove_
#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS)
+int _gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
int gpiod_export_link(struct device *dev, const char *name,
struct gpio_desc *desc);
@@ -675,6 +676,13 @@ void gpiod_unexport(struct gpio_desc *de
#else /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */
+static inline int _gpiod_export(struct gpio_desc *desc,
+ bool direction_may_change,
+ const char *name)
+{
+ return -ENOSYS;
+}
+
static inline int gpiod_export(struct gpio_desc *desc,
bool direction_may_change)
{

View file

@ -0,0 +1,20 @@
Index: linux-5.4.124/drivers/mtd/nand/spi/gigadevice.c
===================================================================
--- linux-5.4.124.orig/drivers/mtd/nand/spi/gigadevice.c
+++ linux-5.4.124/drivers/mtd/nand/spi/gigadevice.c
@@ -242,6 +242,15 @@ static const struct spinand_info gigadev
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
gd5fxgq4xa_ecc_get_status)),
+ SPINAND_INFO("GD5F2GQ4xB", 0xD2,
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
+ gd5fxgq4xa_ecc_get_status)),
SPINAND_INFO("GD5F4GQ4xA", 0xF4,
NAND_MEMORG(1, 2048, 64, 64, 4096, 80, 1, 1, 1),
NAND_ECCREQ(8, 512),

View file

@ -0,0 +1,53 @@
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -75,7 +75,7 @@
}
static const struct spinand_info winbond_spinand_table[] = {
- SPINAND_INFO("W25M02GV", 0xAB,
+ SPINAND_INFO("W25M02GV", 0xAB21,
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2),
NAND_ECCREQ(1, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -84,8 +84,16 @@
0,
SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
SPINAND_SELECT_TARGET(w25m02gv_select_target)),
- SPINAND_INFO("W25N01GV", 0xAA,
+ SPINAND_INFO("W25N01GV", 0xAA21,
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(1, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ 0,
+ SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
+ SPINAND_INFO("W25N02KV", 0xAA22,
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(1, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
@@ -102,17 +110,21 @@
static int winbond_spinand_detect(struct spinand_device *spinand)
{
u8 *id = spinand->id.data;
+ u16 did;
int ret;
/*
* Winbond SPI NAND read ID need a dummy byte,
* so the first byte in raw_id is dummy.
+ * Second and also third byte are device id
*/
if (id[1] != SPINAND_MFR_WINBOND)
return 0;
+ else
+ did = (id[2] << 8) + id[3];
ret = spinand_match_and_init(spinand, winbond_spinand_table,
- ARRAY_SIZE(winbond_spinand_table), id[2]);
+ ARRAY_SIZE(winbond_spinand_table), did);
if (ret)
return ret;

View file

@ -0,0 +1,25 @@
--- a/drivers/mtd/nand/spi/xtx.c
+++ b/drivers/mtd/nand/spi/xtx.c
@@ -37,8 +37,8 @@
if (section)
return -ERANGE;
- region->offset = 8;
- region->length = 40;
+ region->offset = 48;
+ region->length = 16;
return 0;
}
@@ -49,8 +49,9 @@
if (section)
return -ERANGE;
- region->offset = 1;
- region->length = 7;
+ /* Reserve 2 bytes for the BBM. */
+ region->offset = 2;
+ region->length = 62;
return 0;
}

View file

@ -0,0 +1,506 @@
Index: linux-5.4.124/drivers/platform/Kconfig
===================================================================
--- linux-5.4.124.orig/drivers/platform/Kconfig
+++ linux-5.4.124/drivers/platform/Kconfig
@@ -13,5 +13,9 @@ source "drivers/platform/chrome/Kconfig"
source "drivers/platform/mellanox/Kconfig"
source "drivers/platform/olpc/Kconfig"
source "drivers/platform/mikrotik/Kconfig"
+
+if ARCH_QCOM
+source "drivers/platform/ipq/Kconfig"
+endif
Index: linux-5.4.124/drivers/platform/Makefile
===================================================================
--- linux-5.4.124.orig/drivers/platform/Makefile
+++ linux-5.4.124/drivers/platform/Makefile
@@ -9,4 +9,5 @@ obj-$(CONFIG_MIPS) += mips/
obj-$(CONFIG_OLPC_EC) += olpc/
obj-$(CONFIG_GOLDFISH) += goldfish/
obj-$(CONFIG_CHROME_PLATFORMS) += chrome/
obj-$(CONFIG_MIKROTIK) += mikrotik/
+obj-$(CONFIG_ARCH_QCOM) += ipq/
Index: linux-5.4.124/drivers/platform/ipq/bootconfig.c
===================================================================
--- /dev/null
+++ linux-5.4.124/drivers/platform/ipq/bootconfig.c
@@ -0,0 +1,403 @@
+/*
+ * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/seq_file.h>
+#include <asm/setup.h>
+#include <linux/mtd/partitions.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/genhd.h>
+#include <linux/major.h>
+#include <linux/mtd/blktrans.h>
+#include <linux/mtd/mtd.h>
+#include <linux/types.h>
+#include <linux/blkdev.h>
+#include "bootconfig.h"
+
+static struct proc_dir_entry *boot_info_dir;
+static struct proc_dir_entry *partname_dir[NUM_ALT_PARTITION];
+
+static unsigned int num_parts;
+static unsigned int flash_type_emmc;
+
+struct sbl_if_dualboot_info_type_v2 *bootconfig1;
+struct sbl_if_dualboot_info_type_v2 *bootconfig2;
+
+static int getbinary_show(struct seq_file *m, void *v)
+{
+ struct sbl_if_dualboot_info_type_v2 *sbl_info_v2;
+
+ sbl_info_v2 = m->private;
+ memcpy(m->buf + m->count, sbl_info_v2,
+ sizeof(struct sbl_if_dualboot_info_type_v2));
+ m->count += sizeof(struct sbl_if_dualboot_info_type_v2);
+
+ return 0;
+}
+
+static int getbinary_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, getbinary_show, PDE_DATA(inode));
+}
+
+static const struct file_operations getbinary_ops = {
+ .open = getbinary_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int part_upgradepartition_show(struct seq_file *m, void *v)
+{
+ struct per_part_info *part_info_t = m->private;
+
+ /*
+ * In case of NOR\NAND, SBLs change the names of paritions in
+ * such a way that the partition to upgrade is always suffixed
+ * by _1. This is not the case in eMMC as paritions are read
+ * from GPT and we have no control on it. So for eMMC we need
+ * to check and generate the name wheres for NOR\NAND it is
+ * always _1 SBLs should be modified not to change partition
+ * names so that it is consistent with GPT. Till that is done
+ * we will take care of it here.
+ */
+
+ if (flash_type_emmc && (part_info_t->primaryboot))
+ seq_printf(m, "%s\n", part_info_t->name);
+ else
+ seq_printf(m, "%s_1\n", part_info_t->name);
+
+ return 0;
+
+}
+
+static int part_upgradepartition_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, part_upgradepartition_show, PDE_DATA(inode));
+}
+
+static const struct file_operations upgradepartition_ops = {
+ .open = part_upgradepartition_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+
+static ssize_t part_primaryboot_write(struct file *file,
+ const char __user *user,
+ size_t count, loff_t *data)
+{
+ int ret;
+ char optstr[64];
+ struct per_part_info *part_entry;
+ unsigned long val;
+
+ part_entry = PDE_DATA(file_inode(file));
+
+ if (count == 0 || count > sizeof(optstr))
+ return -EINVAL;
+
+ ret = copy_from_user(optstr, user, count);
+ if (ret)
+ return ret;
+
+ optstr[count - 1] = '\0';
+
+ ret = kstrtoul(optstr, 0, &val);
+ if (ret)
+ return ret;
+
+ part_entry->primaryboot = val;
+
+ return count;
+
+}
+
+static int part_primaryboot_show(struct seq_file *m, void *v)
+{
+ struct per_part_info *part_entry;
+
+ part_entry = m->private;
+ seq_printf(m, "%x\n", part_entry->primaryboot);
+ return 0;
+}
+
+static int part_primaryboot_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, part_primaryboot_show, PDE_DATA(inode));
+}
+
+static const struct file_operations primaryboot_ops = {
+ .open = part_primaryboot_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = part_primaryboot_write,
+};
+
+
+struct sbl_if_dualboot_info_type_v2 *read_bootconfig_mtd(
+ struct mtd_info *master,
+ uint64_t offset)
+{
+
+ size_t retlen = 0;
+ struct sbl_if_dualboot_info_type_v2 *bootconfig_mtd;
+ int ret;
+
+ while (mtd_block_isbad(master, offset)) {
+ offset += master->erasesize;
+ if (offset >= master->size) {
+ pr_alert("Bad blocks occurred while reading from \"%s\"\n",
+ master->name);
+ return NULL;
+ }
+ }
+ bootconfig_mtd = kmalloc(sizeof(struct sbl_if_dualboot_info_type_v2),
+ GFP_ATOMIC);
+
+ if (!bootconfig_mtd)
+ return NULL;
+
+ ret = mtd_read(master, offset,
+ sizeof(struct sbl_if_dualboot_info_type_v2),
+ &retlen, (void *)bootconfig_mtd);
+ if (ret < 0) {
+ pr_alert("error occured while reading from \"%s\"\n",
+ master->name);
+ bootconfig_mtd = NULL;
+ kfree(bootconfig_mtd);
+ return NULL;
+ }
+
+ if (bootconfig_mtd->magic_start != SMEM_DUAL_BOOTINFO_MAGIC_START) {
+ pr_alert("Magic not found in \"%s\"\n", master->name);
+ kfree(bootconfig_mtd);
+ return NULL;
+ }
+
+ return bootconfig_mtd;
+}
+
+struct sbl_if_dualboot_info_type_v2 *read_bootconfig_emmc(struct gendisk *disk,
+ struct hd_struct *part)
+{
+ sector_t n;
+ Sector sect;
+ int ret;
+ unsigned char *data;
+ struct sbl_if_dualboot_info_type_v2 *bootconfig_emmc;
+ unsigned ssz;
+ struct block_device *bdev = NULL;
+
+ bdev = bdget_disk(disk, 0);
+ if (!bdev)
+ return NULL;
+
+ bdev->bd_invalidated = 1;
+ ret = blkdev_get(bdev, FMODE_READ , NULL);
+ if (ret)
+ return NULL;
+
+ ssz = bdev_logical_block_size(bdev);
+ bootconfig_emmc = kmalloc(ssz, GFP_ATOMIC);
+ if (!bootconfig_emmc)
+ return NULL;
+
+ n = part->start_sect * (bdev_logical_block_size(bdev) / 512);
+ data = read_dev_sector(bdev, n, &sect);
+ put_dev_sector(sect);
+ blkdev_put(bdev, FMODE_READ);
+ if (!data) {
+ kfree(bootconfig_emmc);
+ return NULL;
+ }
+
+ memcpy(bootconfig_emmc, data, 512);
+
+ if (bootconfig_emmc->magic_start != SMEM_DUAL_BOOTINFO_MAGIC_START) {
+ pr_alert("Magic not found\n");
+ kfree(bootconfig_emmc);
+ return NULL;
+ }
+
+ return bootconfig_emmc;
+}
+
+#define BOOTCONFIG_PARTITION "0:BOOTCONFIG"
+#define BOOTCONFIG_PARTITION1 "0:BOOTCONFIG1"
+#define ROOTFS_PARTITION "rootfs"
+
+static int __init bootconfig_partition_init(void)
+{
+ struct per_part_info *part_info;
+ int i;
+ struct gendisk *disk = NULL;
+ struct disk_part_iter piter;
+ struct hd_struct *part;
+ struct mtd_info *mtd;
+ int partno;
+
+ /*
+ * In case of NOR\NAND boot, there is a chance that emmc
+ * might have bootconfig paritions. This will try to read
+ * the bootconfig partitions and create a proc entry which
+ * is not correct since it is not booting from emmc.
+ */
+
+ mtd = get_mtd_device_nm(ROOTFS_PARTITION);
+ if (IS_ERR(mtd))
+ flash_type_emmc = 1;
+ mtd = get_mtd_device_nm(BOOTCONFIG_PARTITION);
+ if (!IS_ERR(mtd)) {
+
+ bootconfig1 = read_bootconfig_mtd(mtd, 0);
+ mtd = get_mtd_device_nm(BOOTCONFIG_PARTITION1);
+ if (IS_ERR(mtd)) {
+ pr_alert("%s: " BOOTCONFIG_PARTITION1 " not found\n",
+ __func__);
+ return 0;
+ }
+
+ bootconfig2 = read_bootconfig_mtd(mtd, 0);
+ } else if (flash_type_emmc == 1) {
+ flash_type_emmc = 0;
+ disk = get_gendisk(MKDEV(MMC_BLOCK_MAJOR, 0), &partno);
+ if (!disk)
+ return 0;
+
+ disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0);
+ while ((part = disk_part_iter_next(&piter))) {
+
+ if (part->info) {
+ if (!strcmp((char *)part->info->volname,
+ BOOTCONFIG_PARTITION)) {
+ bootconfig1 = read_bootconfig_emmc(disk,
+ part);
+ }
+
+ if (!strcmp((char *)part->info->volname,
+ BOOTCONFIG_PARTITION1)) {
+ bootconfig2 = read_bootconfig_emmc(disk,
+ part);
+ flash_type_emmc = 1;
+ }
+ }
+ }
+ disk_part_iter_exit(&piter);
+
+ }
+
+ if (!bootconfig1) {
+ if (bootconfig2)
+ bootconfig1 = bootconfig2;
+ else
+ return 0;
+ }
+
+ if (!bootconfig2) {
+ if (bootconfig1)
+ bootconfig2 = bootconfig1;
+ else
+ return 0;
+ }
+/*
+ * The following check is to handle the case when an image without
+ * apps upgrade support is upgraded to the image that supports APPS
+ * upgrade. Earlier, the bootconfig file will be chosen based on age,
+ * but now bootconfig1 only is considered and bootconfig2 is a backup.
+ * When bootconfig2 is active in the older image and sysupgrade
+ * is done to it, we copy the bootconfig2 to bootconfig1 so that the
+ * failsafe parameters can be retained.
+ */
+ if (bootconfig2->age > bootconfig1->age)
+ bootconfig1 = bootconfig2;
+
+ num_parts = bootconfig1->numaltpart;
+ bootconfig1->age++;
+ part_info = (struct per_part_info *)bootconfig1->per_part_entry;
+ boot_info_dir = proc_mkdir("boot_info", NULL);
+ if (!boot_info_dir)
+ return 0;
+
+ for (i = 0; i < num_parts; i++) {
+ if (!flash_type_emmc &&
+ (strncmp(part_info[i].name, "kernel",
+ ALT_PART_NAME_LENGTH) == 0))
+ continue;
+
+ partname_dir[i] = proc_mkdir(part_info[i].name, boot_info_dir);
+ if (partname_dir != NULL) {
+ proc_create_data("primaryboot", S_IRUGO,
+ partname_dir[i],
+ &primaryboot_ops,
+ part_info + i);
+ proc_create_data("upgradepartition", S_IRUGO,
+ partname_dir[i],
+ &upgradepartition_ops,
+ part_info + i);
+ }
+ }
+
+ proc_create_data("getbinary_bootconfig", S_IRUGO, boot_info_dir,
+ &getbinary_ops, bootconfig1);
+ proc_create_data("getbinary_bootconfig1", S_IRUGO, boot_info_dir,
+ &getbinary_ops, bootconfig1);
+
+ return 0;
+}
+module_init(bootconfig_partition_init);
+
+static void __exit bootconfig_partition_exit(void)
+{
+ struct per_part_info *part_info;
+ int i;
+
+ if (!bootconfig1)
+ return;
+
+ if (!bootconfig2)
+ return;
+
+ part_info = (struct per_part_info *)bootconfig1->per_part_entry;
+ for (i = 0; i < num_parts; i++) {
+ if (!flash_type_emmc &&
+ (strncmp(part_info[i].name, "kernel",
+ ALT_PART_NAME_LENGTH) == 0))
+ continue;
+
+ remove_proc_entry("primaryboot", partname_dir[i]);
+ remove_proc_entry("upgradepartition", partname_dir[i]);
+ remove_proc_entry(part_info[i].name, boot_info_dir);
+ }
+ remove_proc_entry("getbinary_bootconfig", boot_info_dir);
+ remove_proc_entry("getbinary_bootconfig1", boot_info_dir);
+ remove_proc_entry("boot_info", NULL);
+ kfree(bootconfig1);
+ kfree(bootconfig2);
+}
+
+module_exit(bootconfig_partition_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
Index: linux-5.4.124/drivers/platform/ipq/bootconfig.h
===================================================================
--- /dev/null
+++ linux-5.4.124/drivers/platform/ipq/bootconfig.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _BOOTCONFIG_H_
+#define _BOOTCONFIG_H_
+
+#define BOOTCONFIG_PART_IDX_MAX 21
+
+#define ALT_PART_NAME_LENGTH 16
+struct per_part_info {
+ char name[ALT_PART_NAME_LENGTH];
+ uint32_t primaryboot;
+};
+
+#define NUM_ALT_PARTITION 8
+
+/* version 2 */
+#define SMEM_DUAL_BOOTINFO_MAGIC_START 0xA3A2A1A0
+#define SMEM_DUAL_BOOTINFO_MAGIC_END 0xB3B2B1B0
+
+struct sbl_if_dualboot_info_type_v2 {
+ uint32_t magic_start;
+ uint32_t age;
+ uint32_t numaltpart;
+ struct per_part_info per_part_entry[NUM_ALT_PARTITION];
+ uint32_t magic_end;
+} __packed;
+
+#endif /* _BOOTCONFIG_H_ */
+
Index: linux-5.4.124/drivers/platform/ipq/Kconfig
===================================================================
--- /dev/null
+++ linux-5.4.124/drivers/platform/ipq/Kconfig
@@ -0,0 +1,11 @@
+menu "IPQ specific device drivers"
+ depends on ARCH_QCOM
+
+config BOOTCONFIG_PARTITION
+ tristate "BOOTCONFIG Partition support"
+ help
+ Say Y here if you would like to use hard disks under Linux which
+ were partitioned using MTD/EFI.
+
+endmenu
+
Index: linux-5.4.124/drivers/platform/ipq/Makefile
===================================================================
--- /dev/null
+++ linux-5.4.124/drivers/platform/ipq/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the IPQ specific device drivers.
+#
+
+obj-$(CONFIG_BOOTCONFIG_PARTITION) += bootconfig.o

View file

@ -0,0 +1,53 @@
--- a/fs/jffs2/writev.c
+++ b/fs/jffs2/writev.c
@@ -16,9 +16,18 @@
int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen)
{
+ int ret;
+
+ ret = mtd_writev(c->mtd, vecs, count, to, retlen);
+
if (!jffs2_is_writebuffered(c)) {
if (jffs2_sum_active()) {
int res;
+
+ if (ret ||
+ *retlen != iov_length((struct iovec *) vecs, count))
+ return ret;
+
res = jffs2_sum_add_kvec(c, vecs, count, (uint32_t) to);
if (res) {
return res;
@@ -26,18 +35,22 @@
}
}
- return mtd_writev(c->mtd, vecs, count, to, retlen);
+ return ret;
}
int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t len,
size_t *retlen, const u_char *buf)
{
int ret;
+
ret = mtd_write(c->mtd, ofs, len, retlen, buf);
if (jffs2_sum_active()) {
struct kvec vecs[1];
int res;
+
+ if (ret || *retlen != len)
+ return ret;
vecs[0].iov_base = (unsigned char *) buf;
vecs[0].iov_len = len;
@@ -47,5 +60,6 @@
return res;
}
}
+
return ret;
}

View file

@ -0,0 +1,210 @@
--- a/drivers/net/phy/qca807x.c
+++ b/drivers/net/phy/qca807x.c
@@ -122,9 +122,24 @@
#define PSGMII_MODE_CTRL_AZ_WORKAROUND_MASK GENMASK(3, 0)
#define PSGMII_MMD3_SERDES_CONTROL 0x805a
+#define QCA8075_PHY4_PREFER_FIBER 0x400
+
struct qca807x_gpio_priv {
struct phy_device *phy;
};
+
+/* Phy medium type */
+typedef enum {
+ QCA8075_PHY_MEDIUM_COPPER = 0,
+ QCA8075_PHY_MEDIUM_FIBER = 1, /**< Fiber */
+ QCA8075_PHY_MEDIUM_NULL = 2 /**< NULL */
+} qca8075_phy_medium_t;
+
+static qca8075_phy_medium_t last_phy_medium = QCA8075_PHY_MEDIUM_NULL;
+static int last_phydev_link_state = -1;
+static int copper_link = 0;
+static int fiber_link = 0;
+static int report_last_status = 0;
static int qca807x_get_downshift(struct phy_device *phydev, u8 *data)
{
@@ -400,6 +415,142 @@
}
#endif
+static qca8075_phy_medium_t phy_prefer_medium_get(struct phy_device *phydev)
+{
+ int val;
+ val = phy_read(phydev, QCA807X_CHIP_CONFIGURATION);
+
+ return ((val & QCA8075_PHY4_PREFER_FIBER) ?
+ QCA8075_PHY_MEDIUM_FIBER : QCA8075_PHY_MEDIUM_COPPER);
+}
+
+static qca8075_phy_medium_t phy_active_medium_get(struct phy_device *phydev) {
+ int val;
+ val = phy_read(phydev, QCA807X_MEDIA_SELECT_STATUS);
+
+ if (val & QCA807X_MEDIA_DETECTED_COPPER) {
+ return QCA8075_PHY_MEDIUM_COPPER;
+ } else if ((val & QCA807X_MEDIA_DETECTED_1000_BASE_X) ||
+ (val & QCA807X_MEDIA_DETECTED_100_BASE_FX)) {
+ return QCA8075_PHY_MEDIUM_FIBER;
+ } else {
+ return phy_prefer_medium_get(phydev);
+ }
+}
+
+static int ar40xx_update_link(struct phy_device *phydev)
+{
+ int status = 0, bmcr;
+ qca8075_phy_medium_t phy_medium;
+
+ phy_medium = phy_active_medium_get(phydev);
+
+ /* Do a fake read */
+ bmcr = phy_read(phydev, MII_BMSR);
+ if (bmcr < 0)
+ return bmcr;
+
+ /* Autoneg is being started, therefore disregard BMSR value and
+ * report link as down.
+ */
+ if (bmcr & BMCR_ANRESTART)
+ goto done;
+
+ /* The link state is latched low so that momentary link
+ * drops can be detected. Do not double-read the status
+ * in polling mode to detect such short link drops except
+ * the link was already down.
+ */
+ if (!phy_polling_mode(phydev) || !phydev->link) {
+ status = phy_read(phydev, MII_BMSR);
+ if (status < 0)
+ return status;
+ else if (status & BMSR_LSTATUS)
+ goto done;
+ }
+
+ /* Read link and autonegotiation status */
+ status = phy_read(phydev, MII_BMSR);
+ if (status < 0)
+ return status;
+done:
+ if ( report_last_status > 0 ) {
+ report_last_status = 0;
+ phydev->link = last_phydev_link_state;
+ return 0;
+ }
+ /* reporting copper/fiber link state to netdev */
+ if ((status & BMSR_LSTATUS) == 0) {
+ phydev->link = 0;
+ if (last_phy_medium == phy_medium) { /* medium not changed */
+ if(phydev->link != last_phydev_link_state)
+ report_last_status++;
+ if (phy_medium == QCA8075_PHY_MEDIUM_FIBER)
+ fiber_link = 0;
+ else
+ copper_link = 0;
+ } else { /* medium changed, check current medium*/
+ if (phy_medium == QCA8075_PHY_MEDIUM_FIBER) { /* fiber active*/
+ if (copper_link == 1) { /* copper active, but not preferred*/
+ if(phydev->link == last_phydev_link_state) {
+ phydev->link = !phydev->link; /* toggle link state */
+ report_last_status++;
+ }
+ }
+ fiber_link = 0;
+ } else { /* copper active*/
+ if (fiber_link == 1) { /* fiber active, preferred*/
+ if(phydev->link == last_phydev_link_state) {
+ phydev->link = !phydev->link; /* toggle link state */
+ report_last_status++;
+ }
+ }
+ copper_link = 0;
+ }
+ }
+ } else {
+ phydev->link = 1;
+ if (last_phy_medium == phy_medium){
+ if (phy_medium == QCA8075_PHY_MEDIUM_FIBER)
+ fiber_link = 1;
+ else
+ copper_link = 1;
+ }
+ else {
+ if (phy_medium == QCA8075_PHY_MEDIUM_FIBER) { /* fiber active*/
+ if (copper_link == 1) { /* copper active, but not preferred*/
+ if(phydev->link == last_phydev_link_state) {
+ phydev->link = !phydev->link;
+ report_last_status++;
+ }
+ }
+ fiber_link = 1;
+ } else { /* copper active*/
+ if (fiber_link == 1) { /* fiber active, preferred*/
+ if(phydev->link == last_phydev_link_state) {
+ phydev->link = !phydev->link;
+ report_last_status++;
+ }
+ }
+ copper_link = 1;
+ }
+ }
+ }
+
+ phydev->autoneg_complete = status & BMSR_ANEGCOMPLETE ? 1 : 0;
+
+ /* Consider the case that autoneg was started and "aneg complete"
+ * bit has been reset, but "link up" bit not yet.
+ */
+ if (phydev->autoneg == AUTONEG_ENABLE && !phydev->autoneg_complete)
+ phydev->link = 0;
+
+ last_phy_medium = phy_medium;
+ last_phydev_link_state = phydev->link;
+
+ return 0;
+}
+
static int qca807x_read_copper_status(struct phy_device *phydev, bool combo_port)
{
int ss, err, page, old_link = phydev->link;
@@ -415,7 +566,7 @@
}
/* Update the link, but return if there was an error */
- err = genphy_update_link(phydev);
+ err = ar40xx_update_link(phydev);
if (err)
return err;
@@ -499,7 +650,7 @@
}
/* Update the link, but return if there was an error */
- err = genphy_update_link(phydev);
+ err = ar40xx_update_link(phydev);
if (err)
return err;
@@ -559,7 +710,7 @@
static int qca807x_read_status(struct phy_device *phydev)
{
- int val;
+ int val, err;
/* Check for Combo port */
if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) {
@@ -572,6 +723,11 @@
} else if ((val & QCA807X_MEDIA_DETECTED_1000_BASE_X) ||
(val & QCA807X_MEDIA_DETECTED_100_BASE_FX)) {
qca807x_read_fiber_status(phydev, true);
+ } else {
+ /* Update the link, but return if there was an error */
+ err = ar40xx_update_link(phydev);
+ if (err)
+ return err;
}
} else {
qca807x_read_copper_status(phydev, true);

View file

@ -0,0 +1,63 @@
Index: linux-5.4.124/drivers/net/phy/ar40xx.c
===================================================================
--- linux-5.4.124.orig/drivers/net/phy/ar40xx.c
+++ linux-5.4.124/drivers/net/phy/ar40xx.c
@@ -771,9 +771,58 @@ ar40xx_sw_get_port_link(struct switch_de
return 0;
}
+static int
+ar40xx_sw_delay_reset(struct switch_dev *dev,
+ const struct switch_attr *attr,
+ struct switch_val *value)
+{
+ struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
+ struct mii_bus *bus;
+ int i;
+ u16 val;
+
+ bus = priv->mii_bus;
+ for (i = 0; i < AR40XX_NUM_PORTS - 2; i++) {
+ mdiobus_write(bus, i, MII_CTRL1000, 0);
+ mdiobus_write(bus, i, MII_ADVERTISE, 0);
+ mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
+ ar40xx_phy_dbg_read(priv, i, AR40XX_PHY_DEBUG_0, &val);
+ val |= AR40XX_PHY_MANU_CTRL_EN;
+ ar40xx_phy_dbg_write(priv, i, AR40XX_PHY_DEBUG_0, val);
+ /* disable transmit */
+ ar40xx_phy_dbg_read(priv, i, AR40XX_PHY_DEBUG_2, &val);
+ val &= 0xf00f;
+ ar40xx_phy_dbg_write(priv, i, AR40XX_PHY_DEBUG_2, val);
+ }
+
+ msleep(1000 * value->value.i);
+
+ for (i = 0; i < AR40XX_NUM_PORTS - 2; i++) {
+ ar40xx_phy_dbg_read(priv, i, AR40XX_PHY_DEBUG_0, &val);
+ val &= ~AR40XX_PHY_MANU_CTRL_EN;
+ ar40xx_phy_dbg_write(priv, i, AR40XX_PHY_DEBUG_0, val);
+ mdiobus_write(bus, i,
+ MII_ADVERTISE, ADVERTISE_ALL |
+ ADVERTISE_PAUSE_CAP |
+ ADVERTISE_PAUSE_ASYM);
+ mdiobus_write(bus, i, MII_CTRL1000, ADVERTISE_1000FULL);
+ mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
+ }
+
+ ar40xx_phy_poll_reset(priv);
+
+ return 0;
+}
+
static const struct switch_attr ar40xx_sw_attr_globals[] = {
{
.type = SWITCH_TYPE_INT,
+ .name = "soft_reset",
+ .description = "Switch soft reset with delay (seconds)",
+ .set = ar40xx_sw_delay_reset
+ },
+ {
+ .type = SWITCH_TYPE_INT,
.name = "enable_vlan",
.description = "Enable VLAN mode",
.set = ar40xx_sw_set_vlan,

View file

@ -0,0 +1,151 @@
--- a/drivers/net/phy/ar40xx.c
+++ b/drivers/net/phy/ar40xx.c
@@ -82,6 +82,13 @@
MIB_DESC(1, AR40XX_STATS_TXLATECOL, "TxLateCol"),
};
+static int
+ar40xx_atu_flush(struct ar40xx_priv *);
+
+static int
+ar40xx_atu_dump(struct ar40xx_priv *);
+
+
static u32
ar40xx_read(struct ar40xx_priv *priv, int reg)
{
@@ -810,6 +817,35 @@
}
ar40xx_phy_poll_reset(priv);
+
+ return 0;
+}
+
+static int
+ar40xx_sw_atu_flush(struct switch_dev *dev,
+ const struct switch_attr *attr,
+ struct switch_val *val)
+{
+ struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
+
+ return ar40xx_atu_flush(priv);
+}
+
+static int
+ar40xx_sw_atu_dump(struct switch_dev *dev,
+ const struct switch_attr *attr,
+ struct switch_val *val)
+{
+ struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
+ int len=0;
+
+ len = ar40xx_atu_dump(priv);
+ if(len >= 0){
+ val->value.s = priv->buf;
+ val->len = len;
+ } else {
+ val->len = -1;
+ }
return 0;
}
@@ -868,6 +904,18 @@
.max = AR40XX_NUM_PORTS - 1
},
{
+ .type = SWITCH_TYPE_NOVAL,
+ .name = "flush_arl",
+ .description = "Flush ARL table",
+ .set = ar40xx_sw_atu_flush,
+ },
+ {
+ .type = SWITCH_TYPE_STRING,
+ .name = "dump_arl",
+ .description = "Dump ARL table with mac and port map",
+ .get = ar40xx_sw_atu_dump,
+ },
+ {
.type = SWITCH_TYPE_INT,
.name = "linkdown",
.description = "Link down all the PHYs",
@@ -925,6 +973,65 @@
pr_err("ar40xx: timeout for reg %08x: %08x & %08x != %08x\n",
(unsigned int)reg, t, mask, val);
return -ETIMEDOUT;
+}
+
+static int
+ar40xx_atu_dump(struct ar40xx_priv *priv)
+{
+ u32 ret;
+ u32 i = 0, len = 0, entry_len = 0;
+ volatile u32 reg[4] = {0,0,0,0};
+ u8 addr[ETH_ALEN] = { 0 };
+ char *buf;
+
+ buf = priv->buf;
+ memset(priv->buf, 0, sizeof(priv->buf));
+ do {
+ ret = ar40xx_wait_bit(priv, AR40XX_REG_ATU_FUNC,
+ AR40XX_ATU_FUNC_BUSY, 0);
+ if(ret != 0)
+ return -ETIMEDOUT;
+
+ reg[3] = AR40XX_ATU_FUNC_BUSY | AR40XX_ATU_FUNC_OP_GET_NEXT;
+ ar40xx_write(priv, AR40XX_REG_ATU_DATA0, reg[0]);
+ ar40xx_write(priv, AR40XX_REG_ATU_DATA1, reg[1]);
+ ar40xx_write(priv, AR40XX_REG_ATU_DATA2, reg[2]);
+ ar40xx_write(priv, AR40XX_REG_ATU_FUNC, reg[3]);
+
+ ret = ar40xx_wait_bit(priv, AR40XX_REG_ATU_FUNC,
+ AR40XX_ATU_FUNC_BUSY, 0);
+ if(ret != 0)
+ return -ETIMEDOUT;
+
+ reg[0] = ar40xx_read(priv, AR40XX_REG_ATU_DATA0);
+ reg[1] = ar40xx_read(priv, AR40XX_REG_ATU_DATA1);
+ reg[2] = ar40xx_read(priv, AR40XX_REG_ATU_DATA2);
+ reg[3] = ar40xx_read(priv, AR40XX_REG_ATU_FUNC);
+
+ if((reg[2] & 0xf) == 0)
+ break;
+
+ for(i=2; i<6; i++)
+ addr[i] = (reg[0] >> ((5 - i) << 3)) & 0xff;
+ for(i=0; i<2; i++)
+ addr[i] = (reg[1] >> ((1 - i) << 3)) & 0xff;
+
+ len += snprintf(buf + len, sizeof(priv->buf) - len, "MAC: %02x:%02x:%02x:%02x:%02x:%02x ",
+ addr[0],addr[1],addr[2],addr[3],addr[4],addr[5]);
+ len += snprintf(buf + len, sizeof(priv->buf) - len, "PORTMAP: 0x%02x ", ((reg[1] >> 16) & 0x7f));
+
+ len += snprintf(buf + len, sizeof(priv->buf) - len, "VID: 0x%x ", ((reg[2] >> 8) & 0xfff));
+
+ len += snprintf(buf + len, sizeof(priv->buf) - len, "STATUS: 0x%x\n", ((reg[2] & 0xf) == 0xf ? 1 : 0));
+
+ if (!entry_len)
+ entry_len = len;
+
+ if (sizeof(priv->buf) - len <= entry_len)
+ break;
+ } while(1);
+
+ return len;
}
static int
--- a/drivers/net/phy/ar40xx.h
+++ b/drivers/net/phy/ar40xx.h
@@ -243,6 +243,10 @@
#define AR40XX_PORT_LOOKUP_LOOPBACK BIT(21)
#define AR40XX_PORT_LOOKUP_ING_MIRROR_EN BIT(25)
+#define AR40XX_REG_ATU_DATA0 0x600
+#define AR40XX_REG_ATU_DATA1 0x604
+#define AR40XX_REG_ATU_DATA2 0x608
+
#define AR40XX_REG_ATU_FUNC 0x60c
#define AR40XX_ATU_FUNC_OP BITS(0, 4)
#define AR40XX_ATU_FUNC_OP_NOOP 0x0

View file

@ -0,0 +1,97 @@
--- a/drivers/net/phy/ar40xx.h
+++ b/drivers/net/phy/ar40xx.h
@@ -282,6 +282,13 @@
#define AR40XX_PHY_SPEC_STATUS_DUPLEX BIT(13)
#define AR40XX_PHY_SPEC_STATUS_SPEED BITS(14, 2)
+#define COMBO_PHY_ID 4
+#define QCA807X_CHIP_CONFIGURATION 0x1f /* Chip Configuration Register */
+
+#define QCA8075_PHY4_PREFER_FIBER 0x400
+#define PHY4_PREFER_COPPER 0x0
+#define PHY4_PREFER_FIBER 0x1
+
/* port forwarding state */
enum {
AR40XX_PORT_STATE_DISABLED = 0,
--- a/drivers/net/phy/ar40xx.c
+++ b/drivers/net/phy/ar40xx.c
@@ -612,6 +612,62 @@
ar40xx_port_phy_linkdown(priv);
else
ar40xx_phy_init(priv);
+
+ return 0;
+}
+
+static int phy_prefer_medium_set(struct ar40xx_priv *priv, u16 medium)
+{
+ struct mii_bus *bus;
+ u16 phy_medium;
+
+ bus = priv->mii_bus;
+ phy_medium =
+ mdiobus_read(bus, COMBO_PHY_ID , QCA807X_CHIP_CONFIGURATION);
+
+ if (medium == PHY4_PREFER_FIBER) {
+ phy_medium |= QCA8075_PHY4_PREFER_FIBER;
+ } else {
+ phy_medium &= ~QCA8075_PHY4_PREFER_FIBER;
+ }
+
+ mdiobus_write(bus, COMBO_PHY_ID, QCA807X_CHIP_CONFIGURATION, phy_medium );
+
+ return 0;
+}
+
+static int
+ar40xx_sw_set_preference(struct switch_dev *dev,
+ const struct switch_attr *attr,
+ struct switch_val *val)
+{
+ struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
+ u16 pref;
+ if (val->value.i == 0)
+ pref = PHY4_PREFER_COPPER;
+ else
+ pref = PHY4_PREFER_FIBER;
+
+ phy_prefer_medium_set(priv, pref);
+
+ return 0;
+}
+
+static int
+ar40xx_sw_get_preference(struct switch_dev *dev,
+ const struct switch_attr *attr,
+ struct switch_val *val)
+{
+ struct ar40xx_priv *priv = swdev_to_ar40xx(dev);
+
+ struct mii_bus *bus;
+ u16 phy_medium;
+
+ bus = priv->mii_bus;
+ phy_medium =
+ mdiobus_read(bus, COMBO_PHY_ID , QCA807X_CHIP_CONFIGURATION);
+
+ val->value.i = phy_medium;
return 0;
}
@@ -922,6 +978,14 @@
.set = ar40xx_sw_set_linkdown,
.max = 1
},
+ {
+ .type = SWITCH_TYPE_INT,
+ .name = "preference",
+ .description = "Set fiber/copper combo preference",
+ .set = ar40xx_sw_set_preference,
+ .get = ar40xx_sw_get_preference,
+ .max = 1
+ },
};
static const struct switch_attr ar40xx_sw_attr_port[] = {

View file

@ -0,0 +1,13 @@
Index: linux-5.4.147/drivers/usb/host/xhci.h
===================================================================
--- linux-5.4.147.orig/drivers/usb/host/xhci.h
+++ linux-5.4.147/drivers/usb/host/xhci.h
@@ -1654,7 +1654,7 @@ struct urb_priv {
* (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table,
* meaning 64 ring segments.
* Initial allocated size of the ERST, in number of entries */
-#define ERST_NUM_SEGS 1
+#define ERST_NUM_SEGS 16
/* Initial allocated size of the ERST, in number of entries */
#define ERST_SIZE 64
/* Initial number of event segment rings allocated */

View file

@ -0,0 +1,105 @@
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -273,9 +273,6 @@
writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
controller->base + QUP_OPERATIONAL);
- if (!remainder)
- goto exit;
-
if (is_block_mode) {
num_words = (remainder > words_per_block) ?
words_per_block : remainder;
@@ -305,13 +302,11 @@
* to refresh opflags value because MAX_INPUT_DONE_FLAG may now be
* present and this is used to determine if transaction is complete
*/
-exit:
- if (!remainder) {
- *opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
- if (is_block_mode && *opflags & QUP_OP_MAX_INPUT_DONE_FLAG)
- writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
- controller->base + QUP_OPERATIONAL);
- }
+ *opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
+ if (is_block_mode && *opflags & QUP_OP_MAX_INPUT_DONE_FLAG)
+ writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
+ controller->base + QUP_OPERATIONAL);
+
}
static void spi_qup_write_to_fifo(struct spi_qup *controller, u32 num_words)
@@ -358,10 +353,6 @@
/* ACK by clearing service flag */
writel_relaxed(QUP_OP_OUT_SERVICE_FLAG,
controller->base + QUP_OPERATIONAL);
-
- /* make sure the interrupt is valid */
- if (!remainder)
- return;
if (is_block_mode) {
num_words = (remainder > words_per_block) ?
@@ -576,24 +567,10 @@
return 0;
}
-static bool spi_qup_data_pending(struct spi_qup *controller)
-{
- unsigned int remainder_tx, remainder_rx;
-
- remainder_tx = DIV_ROUND_UP(spi_qup_len(controller) -
- controller->tx_bytes, controller->w_size);
-
- remainder_rx = DIV_ROUND_UP(spi_qup_len(controller) -
- controller->rx_bytes, controller->w_size);
-
- return remainder_tx || remainder_rx;
-}
-
static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
{
struct spi_qup *controller = dev_id;
u32 opflags, qup_err, spi_err;
- unsigned long flags;
int error = 0;
qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS);
@@ -625,11 +602,6 @@
error = -EIO;
}
- spin_lock_irqsave(&controller->lock, flags);
- if (!controller->error)
- controller->error = error;
- spin_unlock_irqrestore(&controller->lock, flags);
-
if (spi_qup_is_dma_xfer(controller->mode)) {
writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
} else {
@@ -638,21 +610,10 @@
if (opflags & QUP_OP_OUT_SERVICE_FLAG)
spi_qup_write(controller);
-
- if (!spi_qup_data_pending(controller))
- complete(&controller->done);
- }
-
- if (error)
+ }
+
+ if ((opflags & QUP_OP_MAX_INPUT_DONE_FLAG) || error)
complete(&controller->done);
-
- if (opflags & QUP_OP_MAX_INPUT_DONE_FLAG) {
- if (!spi_qup_is_dma_xfer(controller->mode)) {
- if (spi_qup_data_pending(controller))
- return IRQ_HANDLED;
- }
- complete(&controller->done);
- }
return IRQ_HANDLED;
}

View file

@ -0,0 +1,21 @@
Index: linux-5.4.147/drivers/mtd/nand/spi/micron.c
===================================================================
--- linux-5.4.147.orig/drivers/mtd/nand/spi/micron.c
+++ linux-5.4.147/drivers/mtd/nand/spi/micron.c
@@ -91,7 +91,7 @@ static int mt29f2g01abagd_ecc_get_status
}
static const struct spinand_info micron_spinand_table[] = {
- SPINAND_INFO("MT29F2G01ABAGD", 0x24,
+ SPINAND_INFO("MT29F2G01ABAGD", 0x24, // Note: XTX nand flash XT26G02E have same MAN_ID and DEV_ID
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -128,6 +128,6 @@ static const struct spinand_manufacturer
const struct spinand_manufacturer micron_spinand_manufacturer = {
.id = SPINAND_MFR_MICRON,
- .name = "Micron",
+ .name = "Micron / XTX",
.ops = &micron_spinand_manuf_ops,
};