mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-25 08:21:14 +00:00
ramips: 5.10: copy patches from 5.4
Strict copy, no changes made. Signed-off-by: Ilya Lipnitskiy <ilya.lipnitskiy@gmail.com>
This commit is contained in:
parent
a9966793e8
commit
eda836e390
@ -0,0 +1,192 @@
|
|||||||
|
From: Paul Burton <paul.burton@mips.com>
|
||||||
|
Date: Wed, 9 Oct 2019 23:09:45 +0000
|
||||||
|
Subject: MIPS: cmdline: Clean up boot_command_line initialization
|
||||||
|
|
||||||
|
Our current code to initialize boot_command_line is a mess. Some of this
|
||||||
|
is due to the addition of too many options over the years, and some of
|
||||||
|
this is due to workarounds for early_init_dt_scan_chosen() performing
|
||||||
|
actions specific to options from other architectures that probably
|
||||||
|
shouldn't be in generic code.
|
||||||
|
|
||||||
|
Clean this up by introducing a new bootcmdline_init() function that
|
||||||
|
simplifies the initialization somewhat. The major changes are:
|
||||||
|
|
||||||
|
- Because bootcmdline_init() is a function it can return early in the
|
||||||
|
CONFIG_CMDLINE_OVERRIDE case.
|
||||||
|
|
||||||
|
- We clear boot_command_line rather than inheriting whatever
|
||||||
|
early_init_dt_scan_chosen() may have left us. This means we no longer
|
||||||
|
need to set boot_command_line to a space character in an attempt to
|
||||||
|
prevent early_init_dt_scan_chosen() from copying CONFIG_CMDLINE into
|
||||||
|
boot_command_line without us knowing about it.
|
||||||
|
|
||||||
|
- Indirection via USE_PROM_CMDLINE, USE_DTB_CMDLINE, EXTEND_WITH_PROM &
|
||||||
|
BUILTIN_EXTEND_WITH_PROM macros is removed; they seemingly served only
|
||||||
|
to obfuscate the code.
|
||||||
|
|
||||||
|
- The logic is cleaner, clearer & commented.
|
||||||
|
|
||||||
|
Two minor drawbacks of this approach are:
|
||||||
|
|
||||||
|
1) We call of_scan_flat_dt(), which means we scan through the DT again.
|
||||||
|
The overhead is fairly minimal & shouldn't be noticeable.
|
||||||
|
|
||||||
|
2) cmdline_scan_chosen() duplicates a small amount of the logic from
|
||||||
|
early_init_dt_scan_chosen(). Alternatives might be to allow the
|
||||||
|
generic FDT code to keep & expose a copy of the arguments taken from
|
||||||
|
the /chosen node's bootargs property, or to introduce a function like
|
||||||
|
early_init_dt_scan_chosen() that retrieves them without modification
|
||||||
|
to handle CONFIG_CMDLINE. Neither of these sounds particularly
|
||||||
|
cleaner though, and this way we at least keep the extra work in
|
||||||
|
arch/mips.
|
||||||
|
|
||||||
|
Origin: upstream, https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7784cac697351f0cc0a4bb619594c0c99348c5aa
|
||||||
|
Signed-off-by: Paul Burton <paul.burton@mips.com>
|
||||||
|
Cc: linux-mips@vger.kernel.org
|
||||||
|
|
||||||
|
--- a/arch/mips/kernel/setup.c
|
||||||
|
+++ b/arch/mips/kernel/setup.c
|
||||||
|
@@ -538,11 +538,88 @@ static void __init check_kernel_sections
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-#define USE_PROM_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER)
|
||||||
|
-#define USE_DTB_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB)
|
||||||
|
-#define EXTEND_WITH_PROM IS_ENABLED(CONFIG_MIPS_CMDLINE_DTB_EXTEND)
|
||||||
|
-#define BUILTIN_EXTEND_WITH_PROM \
|
||||||
|
- IS_ENABLED(CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND)
|
||||||
|
+static void __init bootcmdline_append(const char *s, size_t max)
|
||||||
|
+{
|
||||||
|
+ if (!s[0] || !max)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ if (boot_command_line[0])
|
||||||
|
+ strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
|
||||||
|
+
|
||||||
|
+ strlcat(boot_command_line, s, max);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int __init bootcmdline_scan_chosen(unsigned long node, const char *uname,
|
||||||
|
+ int depth, void *data)
|
||||||
|
+{
|
||||||
|
+ bool *dt_bootargs = data;
|
||||||
|
+ const char *p;
|
||||||
|
+ int l;
|
||||||
|
+
|
||||||
|
+ if (depth != 1 || !data ||
|
||||||
|
+ (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ p = of_get_flat_dt_prop(node, "bootargs", &l);
|
||||||
|
+ if (p != NULL && l > 0) {
|
||||||
|
+ bootcmdline_append(p, min(l, COMMAND_LINE_SIZE));
|
||||||
|
+ *dt_bootargs = true;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 1;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void __init bootcmdline_init(char **cmdline_p)
|
||||||
|
+{
|
||||||
|
+ bool dt_bootargs = false;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * If CMDLINE_OVERRIDE is enabled then initializing the command line is
|
||||||
|
+ * trivial - we simply use the built-in command line unconditionally &
|
||||||
|
+ * unmodified.
|
||||||
|
+ */
|
||||||
|
+ if (IS_ENABLED(CONFIG_CMDLINE_OVERRIDE)) {
|
||||||
|
+ strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * If the user specified a built-in command line &
|
||||||
|
+ * MIPS_CMDLINE_BUILTIN_EXTEND, then the built-in command line is
|
||||||
|
+ * prepended to arguments from the bootloader or DT so we'll copy them
|
||||||
|
+ * to the start of boot_command_line here. Otherwise, empty
|
||||||
|
+ * boot_command_line to undo anything early_init_dt_scan_chosen() did.
|
||||||
|
+ */
|
||||||
|
+ if (IS_ENABLED(CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND))
|
||||||
|
+ strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
|
||||||
|
+ else
|
||||||
|
+ boot_command_line[0] = 0;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * If we're configured to take boot arguments from DT, look for those
|
||||||
|
+ * now.
|
||||||
|
+ */
|
||||||
|
+ if (IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB))
|
||||||
|
+ of_scan_flat_dt(bootcmdline_scan_chosen, &dt_bootargs);
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * If we didn't get any arguments from DT (regardless of whether that's
|
||||||
|
+ * because we weren't configured to look for them, or because we looked
|
||||||
|
+ * & found none) then we'll take arguments from the bootloader.
|
||||||
|
+ * plat_mem_setup() should have filled arcs_cmdline with arguments from
|
||||||
|
+ * the bootloader.
|
||||||
|
+ */
|
||||||
|
+ if (IS_ENABLED(CONFIG_MIPS_CMDLINE_DTB_EXTEND) || !dt_bootargs)
|
||||||
|
+ bootcmdline_append(arcs_cmdline, COMMAND_LINE_SIZE);
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * If the user specified a built-in command line & we didn't already
|
||||||
|
+ * prepend it, we append it to boot_command_line here.
|
||||||
|
+ */
|
||||||
|
+ if (IS_ENABLED(CONFIG_CMDLINE_BOOL) &&
|
||||||
|
+ !IS_ENABLED(CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND))
|
||||||
|
+ bootcmdline_append(builtin_cmdline, COMMAND_LINE_SIZE);
|
||||||
|
+}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* arch_mem_init - initialize memory management subsystem
|
||||||
|
@@ -570,48 +647,12 @@ static void __init arch_mem_init(char **
|
||||||
|
{
|
||||||
|
extern void plat_mem_setup(void);
|
||||||
|
|
||||||
|
- /*
|
||||||
|
- * Initialize boot_command_line to an innocuous but non-empty string in
|
||||||
|
- * order to prevent early_init_dt_scan_chosen() from copying
|
||||||
|
- * CONFIG_CMDLINE into it without our knowledge. We handle
|
||||||
|
- * CONFIG_CMDLINE ourselves below & don't want to duplicate its
|
||||||
|
- * content because repeating arguments can be problematic.
|
||||||
|
- */
|
||||||
|
- strlcpy(boot_command_line, " ", COMMAND_LINE_SIZE);
|
||||||
|
-
|
||||||
|
/* call board setup routine */
|
||||||
|
plat_mem_setup();
|
||||||
|
memblock_set_bottom_up(true);
|
||||||
|
|
||||||
|
-#if defined(CONFIG_CMDLINE_BOOL) && defined(CONFIG_CMDLINE_OVERRIDE)
|
||||||
|
- strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
|
||||||
|
-#else
|
||||||
|
- if ((USE_PROM_CMDLINE && arcs_cmdline[0]) ||
|
||||||
|
- (USE_DTB_CMDLINE && !boot_command_line[0]))
|
||||||
|
- strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
|
||||||
|
-
|
||||||
|
- if (EXTEND_WITH_PROM && arcs_cmdline[0]) {
|
||||||
|
- if (boot_command_line[0])
|
||||||
|
- strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
|
||||||
|
- strlcat(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
-#if defined(CONFIG_CMDLINE_BOOL)
|
||||||
|
- if (builtin_cmdline[0]) {
|
||||||
|
- if (boot_command_line[0])
|
||||||
|
- strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
|
||||||
|
- strlcat(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- if (BUILTIN_EXTEND_WITH_PROM && arcs_cmdline[0]) {
|
||||||
|
- if (boot_command_line[0])
|
||||||
|
- strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
|
||||||
|
- strlcat(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
|
||||||
|
- }
|
||||||
|
-#endif
|
||||||
|
-#endif
|
||||||
|
+ bootcmdline_init(cmdline_p);
|
||||||
|
strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
|
||||||
|
-
|
||||||
|
*cmdline_p = command_line;
|
||||||
|
|
||||||
|
parse_early_param();
|
@ -0,0 +1,44 @@
|
|||||||
|
From b7340422cc16c5deff100812f38114bb5ec81203 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Paul Burton <paul.burton@mips.com>
|
||||||
|
Date: Sat, 12 Oct 2019 20:43:36 +0000
|
||||||
|
Subject: [PATCH] MIPS: Always define builtin_cmdline
|
||||||
|
|
||||||
|
Commit 7784cac69735 ("MIPS: cmdline: Clean up boot_command_line
|
||||||
|
initialization") made use of builtin_cmdline conditional upon plain C if
|
||||||
|
statements rather than preprocessor #ifdef's. This caused build failures
|
||||||
|
for configurations with CONFIG_CMDLINE_BOOL=n where builtin_cmdline
|
||||||
|
wasn't defined, for example:
|
||||||
|
|
||||||
|
arch/mips/kernel/setup.c: In function 'bootcmdline_init':
|
||||||
|
>> arch/mips/kernel/setup.c:582:30: error: 'builtin_cmdline' undeclared
|
||||||
|
(first use in this function); did you mean 'builtin_driver'?
|
||||||
|
strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
|
||||||
|
^~~~~~~~~~~~~~~
|
||||||
|
builtin_driver
|
||||||
|
arch/mips/kernel/setup.c:582:30: note: each undeclared identifier is
|
||||||
|
reported only once for each function it appears in
|
||||||
|
|
||||||
|
Fix this by defining builtin_cmdline as an empty string in the affected
|
||||||
|
configurations. All of the paths that use it should be optimized out
|
||||||
|
anyway so the data itself gets optimized away too.
|
||||||
|
|
||||||
|
Signed-off-by: Paul Burton <paul.burton@mips.com>
|
||||||
|
Fixes: 7784cac69735 ("MIPS: cmdline: Clean up boot_command_line initialization")
|
||||||
|
Reported-by: kbuild test robot <lkp@intel.com>
|
||||||
|
Reported-by: Nathan Chancellor <natechancellor@gmail.com>
|
||||||
|
Cc: linux-mips@vger.kernel.org
|
||||||
|
---
|
||||||
|
arch/mips/kernel/setup.c | 2 ++
|
||||||
|
1 file changed, 2 insertions(+)
|
||||||
|
|
||||||
|
--- a/arch/mips/kernel/setup.c
|
||||||
|
+++ b/arch/mips/kernel/setup.c
|
||||||
|
@@ -68,6 +68,8 @@ char __initdata arcs_cmdline[COMMAND_LIN
|
||||||
|
|
||||||
|
#ifdef CONFIG_CMDLINE_BOOL
|
||||||
|
static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE;
|
||||||
|
+#else
|
||||||
|
+static const char builtin_cmdline[] __initconst = "";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
@ -0,0 +1,45 @@
|
|||||||
|
From: Tobias Wolf <dev-NTEO@vplace.de>
|
||||||
|
Subject: [v2] MIPS: Fix memory reservation in bootmem_init for certain non-usermem setups
|
||||||
|
|
||||||
|
Commit 67a3ba25aa95 ("MIPS: Fix incorrect mem=X@Y handling") introduced a new
|
||||||
|
issue for rt288x where "PHYS_OFFSET" is 0x0 but the calculated "ramstart" is
|
||||||
|
not. As the prerequisite of custom memory map has been removed, this results
|
||||||
|
in the full memory range of 0x0 - 0x8000000 to be marked as reserved for this
|
||||||
|
platform.
|
||||||
|
|
||||||
|
v2: Correctly compare that usermem is not null.
|
||||||
|
|
||||||
|
This patch adds the originally intended prerequisite again.
|
||||||
|
|
||||||
|
Signed-off-by: Tobias Wolf <dev-NTEO@vplace.de>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/arch/mips/kernel/setup.c
|
||||||
|
+++ b/arch/mips/kernel/setup.c
|
||||||
|
@@ -287,6 +287,8 @@ static unsigned long __init init_initrd(
|
||||||
|
* Initialize the bootmem allocator. It also setup initrd related data
|
||||||
|
* if needed.
|
||||||
|
*/
|
||||||
|
+static int usermem __initdata;
|
||||||
|
+
|
||||||
|
#if defined(CONFIG_SGI_IP27) || (defined(CONFIG_CPU_LOONGSON3) && defined(CONFIG_NUMA))
|
||||||
|
|
||||||
|
static void __init bootmem_init(void)
|
||||||
|
@@ -325,7 +327,7 @@ static void __init bootmem_init(void)
|
||||||
|
/*
|
||||||
|
* Reserve any memory between the start of RAM and PHYS_OFFSET
|
||||||
|
*/
|
||||||
|
- if (ramstart > PHYS_OFFSET)
|
||||||
|
+ if (usermem && ramstart > PHYS_OFFSET)
|
||||||
|
memblock_reserve(PHYS_OFFSET, ramstart - PHYS_OFFSET);
|
||||||
|
|
||||||
|
if (PFN_UP(ramstart) > ARCH_PFN_OFFSET) {
|
||||||
|
@@ -386,8 +388,6 @@ static void __init bootmem_init(void)
|
||||||
|
|
||||||
|
#endif /* CONFIG_SGI_IP27 */
|
||||||
|
|
||||||
|
-static int usermem __initdata;
|
||||||
|
-
|
||||||
|
static int __init early_parse_mem(char *p)
|
||||||
|
{
|
||||||
|
phys_addr_t start, size;
|
@ -0,0 +1,82 @@
|
|||||||
|
From ce3d4a4111a5f7e6b4e74bceae5faa6ce388e8ec Mon Sep 17 00:00:00 2001
|
||||||
|
From: John Crispin <blogic@openwrt.org>
|
||||||
|
Date: Sun, 14 Jul 2013 23:08:11 +0200
|
||||||
|
Subject: [PATCH 05/53] MIPS: use set_mode() to enable/disable the cevt-r4k
|
||||||
|
irq
|
||||||
|
|
||||||
|
Signed-off-by: John Crispin <blogic@openwrt.org>
|
||||||
|
---
|
||||||
|
arch/mips/ralink/Kconfig | 5 +++++
|
||||||
|
1 file changed, 5 insertions(+)
|
||||||
|
|
||||||
|
--- a/arch/mips/ralink/Kconfig
|
||||||
|
+++ b/arch/mips/ralink/Kconfig
|
||||||
|
@@ -1,12 +1,17 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
if RALINK
|
||||||
|
|
||||||
|
+config CEVT_SYSTICK_QUIRK
|
||||||
|
+ bool
|
||||||
|
+ default n
|
||||||
|
+
|
||||||
|
config CLKEVT_RT3352
|
||||||
|
bool
|
||||||
|
depends on SOC_RT305X || SOC_MT7620
|
||||||
|
default y
|
||||||
|
select TIMER_OF
|
||||||
|
select CLKSRC_MMIO
|
||||||
|
+ select CEVT_SYSTICK_QUIRK
|
||||||
|
|
||||||
|
config RALINK_ILL_ACC
|
||||||
|
bool
|
||||||
|
--- a/arch/mips/kernel/cevt-r4k.c
|
||||||
|
+++ b/arch/mips/kernel/cevt-r4k.c
|
||||||
|
@@ -15,6 +15,26 @@
|
||||||
|
#include <asm/time.h>
|
||||||
|
#include <asm/cevt-r4k.h>
|
||||||
|
|
||||||
|
+static int mips_state_oneshot(struct clock_event_device *evt)
|
||||||
|
+{
|
||||||
|
+ if (!cp0_timer_irq_installed) {
|
||||||
|
+ cp0_timer_irq_installed = 1;
|
||||||
|
+ setup_irq(evt->irq, &c0_compare_irqaction);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int mips_state_shutdown(struct clock_event_device *evt)
|
||||||
|
+{
|
||||||
|
+ if (cp0_timer_irq_installed) {
|
||||||
|
+ cp0_timer_irq_installed = 0;
|
||||||
|
+ remove_irq(evt->irq, &c0_compare_irqaction);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int mips_next_event(unsigned long delta,
|
||||||
|
struct clock_event_device *evt)
|
||||||
|
{
|
||||||
|
@@ -281,17 +301,21 @@ int r4k_clockevent_init(void)
|
||||||
|
cd->rating = 300;
|
||||||
|
cd->irq = irq;
|
||||||
|
cd->cpumask = cpumask_of(cpu);
|
||||||
|
+ cd->set_state_shutdown = mips_state_shutdown;
|
||||||
|
+ cd->set_state_oneshot = mips_state_oneshot;
|
||||||
|
cd->set_next_event = mips_next_event;
|
||||||
|
cd->event_handler = mips_event_handler;
|
||||||
|
|
||||||
|
clockevents_config_and_register(cd, mips_hpt_frequency, min_delta, 0x7fffffff);
|
||||||
|
|
||||||
|
+#ifndef CONFIG_CEVT_SYSTICK_QUIRK
|
||||||
|
if (cp0_timer_irq_installed)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
cp0_timer_irq_installed = 1;
|
||||||
|
|
||||||
|
setup_irq(irq, &c0_compare_irqaction);
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,200 @@
|
|||||||
|
From bd30f19a006fb52bac80c6463c49dd2f4159f4ac Mon Sep 17 00:00:00 2001
|
||||||
|
From: John Crispin <blogic@openwrt.org>
|
||||||
|
Date: Sun, 28 Jul 2013 16:26:41 +0200
|
||||||
|
Subject: [PATCH 06/53] MIPS: ralink: add cpu frequency scaling
|
||||||
|
|
||||||
|
This feature will break udelay() and cause the delay loop to have longer delays
|
||||||
|
when the frequency is scaled causing a performance hit.
|
||||||
|
|
||||||
|
Signed-off-by: John Crispin <blogic@openwrt.org>
|
||||||
|
---
|
||||||
|
arch/mips/ralink/cevt-rt3352.c | 38 ++++++++++++++++++++++++++++++++++++++
|
||||||
|
1 file changed, 38 insertions(+)
|
||||||
|
|
||||||
|
--- a/arch/mips/ralink/cevt-rt3352.c
|
||||||
|
+++ b/arch/mips/ralink/cevt-rt3352.c
|
||||||
|
@@ -29,6 +29,10 @@
|
||||||
|
/* enable the counter */
|
||||||
|
#define CFG_CNT_EN 0x1
|
||||||
|
|
||||||
|
+/* mt7620 frequency scaling defines */
|
||||||
|
+#define CLK_LUT_CFG 0x40
|
||||||
|
+#define SLEEP_EN BIT(31)
|
||||||
|
+
|
||||||
|
struct systick_device {
|
||||||
|
void __iomem *membase;
|
||||||
|
struct clock_event_device dev;
|
||||||
|
@@ -36,21 +40,53 @@ struct systick_device {
|
||||||
|
int freq_scale;
|
||||||
|
};
|
||||||
|
|
||||||
|
+static void (*systick_freq_scaling)(struct systick_device *sdev, int status);
|
||||||
|
+
|
||||||
|
static int systick_set_oneshot(struct clock_event_device *evt);
|
||||||
|
static int systick_shutdown(struct clock_event_device *evt);
|
||||||
|
|
||||||
|
+static inline void mt7620_freq_scaling(struct systick_device *sdev, int status)
|
||||||
|
+{
|
||||||
|
+ if (sdev->freq_scale == status)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ sdev->freq_scale = status;
|
||||||
|
+
|
||||||
|
+ pr_info("%s: %s autosleep mode\n", sdev->dev.name,
|
||||||
|
+ (status) ? ("enable") : ("disable"));
|
||||||
|
+ if (status)
|
||||||
|
+ rt_sysc_w32(rt_sysc_r32(CLK_LUT_CFG) | SLEEP_EN, CLK_LUT_CFG);
|
||||||
|
+ else
|
||||||
|
+ rt_sysc_w32(rt_sysc_r32(CLK_LUT_CFG) & ~SLEEP_EN, CLK_LUT_CFG);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline unsigned int read_count(struct systick_device *sdev)
|
||||||
|
+{
|
||||||
|
+ return ioread32(sdev->membase + SYSTICK_COUNT);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline unsigned int read_compare(struct systick_device *sdev)
|
||||||
|
+{
|
||||||
|
+ return ioread32(sdev->membase + SYSTICK_COMPARE);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void write_compare(struct systick_device *sdev, unsigned int val)
|
||||||
|
+{
|
||||||
|
+ iowrite32(val, sdev->membase + SYSTICK_COMPARE);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int systick_next_event(unsigned long delta,
|
||||||
|
struct clock_event_device *evt)
|
||||||
|
{
|
||||||
|
struct systick_device *sdev;
|
||||||
|
- u32 count;
|
||||||
|
+ int res;
|
||||||
|
|
||||||
|
sdev = container_of(evt, struct systick_device, dev);
|
||||||
|
- count = ioread32(sdev->membase + SYSTICK_COUNT);
|
||||||
|
- count = (count + delta) % SYSTICK_FREQ;
|
||||||
|
- iowrite32(count, sdev->membase + SYSTICK_COMPARE);
|
||||||
|
+ delta += read_count(sdev);
|
||||||
|
+ write_compare(sdev, delta);
|
||||||
|
+ res = ((int)(read_count(sdev) - delta) >= 0) ? -ETIME : 0;
|
||||||
|
|
||||||
|
- return 0;
|
||||||
|
+ return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void systick_event_handler(struct clock_event_device *dev)
|
||||||
|
@@ -60,20 +96,25 @@ static void systick_event_handler(struct
|
||||||
|
|
||||||
|
static irqreturn_t systick_interrupt(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
- struct clock_event_device *dev = (struct clock_event_device *) dev_id;
|
||||||
|
+ int ret = 0;
|
||||||
|
+ struct clock_event_device *cdev;
|
||||||
|
+ struct systick_device *sdev;
|
||||||
|
|
||||||
|
- dev->event_handler(dev);
|
||||||
|
+ if (read_c0_cause() & STATUSF_IP7) {
|
||||||
|
+ cdev = (struct clock_event_device *) dev_id;
|
||||||
|
+ sdev = container_of(cdev, struct systick_device, dev);
|
||||||
|
+
|
||||||
|
+ /* Clear Count/Compare Interrupt */
|
||||||
|
+ write_compare(sdev, read_compare(sdev));
|
||||||
|
+ cdev->event_handler(cdev);
|
||||||
|
+ ret = 1;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- return IRQ_HANDLED;
|
||||||
|
+ return IRQ_RETVAL(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct systick_device systick = {
|
||||||
|
.dev = {
|
||||||
|
- /*
|
||||||
|
- * cevt-r4k uses 300, make sure systick
|
||||||
|
- * gets used if available
|
||||||
|
- */
|
||||||
|
- .rating = 310,
|
||||||
|
.features = CLOCK_EVT_FEAT_ONESHOT,
|
||||||
|
.set_next_event = systick_next_event,
|
||||||
|
.set_state_shutdown = systick_shutdown,
|
||||||
|
@@ -95,9 +136,15 @@ static int systick_shutdown(struct clock
|
||||||
|
sdev = container_of(evt, struct systick_device, dev);
|
||||||
|
|
||||||
|
if (sdev->irq_requested)
|
||||||
|
- free_irq(systick.dev.irq, &systick_irqaction);
|
||||||
|
+ remove_irq(systick.dev.irq, &systick_irqaction);
|
||||||
|
sdev->irq_requested = 0;
|
||||||
|
- iowrite32(0, systick.membase + SYSTICK_CONFIG);
|
||||||
|
+ iowrite32(CFG_CNT_EN, systick.membase + SYSTICK_CONFIG);
|
||||||
|
+
|
||||||
|
+ if (systick_freq_scaling)
|
||||||
|
+ systick_freq_scaling(sdev, 0);
|
||||||
|
+
|
||||||
|
+ if (systick_freq_scaling)
|
||||||
|
+ systick_freq_scaling(sdev, 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@@ -117,34 +164,48 @@ static int systick_set_oneshot(struct cl
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static const struct of_device_id systick_match[] = {
|
||||||
|
+ { .compatible = "ralink,mt7620a-systick", .data = mt7620_freq_scaling},
|
||||||
|
+ {},
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
static int __init ralink_systick_init(struct device_node *np)
|
||||||
|
{
|
||||||
|
+ const struct of_device_id *match;
|
||||||
|
+ int rating = 200;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
systick.membase = of_iomap(np, 0);
|
||||||
|
if (!systick.membase)
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
|
- systick_irqaction.name = np->name;
|
||||||
|
- systick.dev.name = np->name;
|
||||||
|
- clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60);
|
||||||
|
- systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev);
|
||||||
|
- systick.dev.max_delta_ticks = 0x7fff;
|
||||||
|
- systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev);
|
||||||
|
- systick.dev.min_delta_ticks = 0x3;
|
||||||
|
+ match = of_match_node(systick_match, np);
|
||||||
|
+ if (match) {
|
||||||
|
+ systick_freq_scaling = match->data;
|
||||||
|
+ /*
|
||||||
|
+ * cevt-r4k uses 300, make sure systick
|
||||||
|
+ * gets used if available
|
||||||
|
+ */
|
||||||
|
+ rating = 310;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* enable counter than register clock source */
|
||||||
|
+ iowrite32(CFG_CNT_EN, systick.membase + SYSTICK_CONFIG);
|
||||||
|
+ clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
|
||||||
|
+ SYSTICK_FREQ, rating, 16, clocksource_mmio_readl_up);
|
||||||
|
+
|
||||||
|
+ /* register clock event */
|
||||||
|
systick.dev.irq = irq_of_parse_and_map(np, 0);
|
||||||
|
if (!systick.dev.irq) {
|
||||||
|
pr_err("%pOFn: request_irq failed", np);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
- ret = clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
|
||||||
|
- SYSTICK_FREQ, 301, 16,
|
||||||
|
- clocksource_mmio_readl_up);
|
||||||
|
- if (ret)
|
||||||
|
- return ret;
|
||||||
|
-
|
||||||
|
- clockevents_register_device(&systick.dev);
|
||||||
|
+ systick_irqaction.name = np->name;
|
||||||
|
+ systick.dev.name = np->name;
|
||||||
|
+ systick.dev.rating = rating;
|
||||||
|
+ systick.dev.cpumask = cpumask_of(0);
|
||||||
|
+ clockevents_config_and_register(&systick.dev, SYSTICK_FREQ, 0x3, 0x7fff);
|
||||||
|
|
||||||
|
pr_info("%pOFn: running - mult: %d, shift: %d\n",
|
||||||
|
np, systick.dev.mult, systick.dev.shift);
|
@ -0,0 +1,21 @@
|
|||||||
|
From 67b7bff0fd364c194e653f69baa623ba2141bd4c Mon Sep 17 00:00:00 2001
|
||||||
|
From: John Crispin <blogic@openwrt.org>
|
||||||
|
Date: Mon, 4 Aug 2014 18:46:02 +0200
|
||||||
|
Subject: [PATCH 07/53] MIPS: ralink: copy the commandline from the devicetree
|
||||||
|
|
||||||
|
Signed-off-by: John Crispin <blogic@openwrt.org>
|
||||||
|
---
|
||||||
|
arch/mips/ralink/of.c | 2 ++
|
||||||
|
1 file changed, 2 insertions(+)
|
||||||
|
|
||||||
|
--- a/arch/mips/ralink/of.c
|
||||||
|
+++ b/arch/mips/ralink/of.c
|
||||||
|
@@ -80,6 +80,8 @@ void __init plat_mem_setup(void)
|
||||||
|
|
||||||
|
__dt_setup_arch(dtb);
|
||||||
|
|
||||||
|
+ strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
|
||||||
|
+
|
||||||
|
of_scan_flat_dt(early_init_dt_find_memory, NULL);
|
||||||
|
if (memory_dtb)
|
||||||
|
of_scan_flat_dt(early_init_dt_scan_memory, NULL);
|
@ -0,0 +1,63 @@
|
|||||||
|
From f15d27f9c90ede4b16eb37f9ae573ef81c2b6996 Mon Sep 17 00:00:00 2001
|
||||||
|
From: David Bauer <mail@david-bauer.net>
|
||||||
|
Date: Thu, 31 Dec 2020 18:49:12 +0100
|
||||||
|
Subject: [PATCH] MIPS: add bootargs-override property
|
||||||
|
|
||||||
|
Add support for the bootargs-override property to the chosen node
|
||||||
|
similar to the one used on ipq806x or mpc85xx.
|
||||||
|
|
||||||
|
This is necessary, as the U-Boot used on some boards, notably the
|
||||||
|
Ubiquiti UniFi 6 Lite, overwrite the bootargs property of the chosen
|
||||||
|
node leading to a kernel panic when loading OpenWrt.
|
||||||
|
|
||||||
|
Signed-off-by: David Bauer <mail@david-bauer.net>
|
||||||
|
---
|
||||||
|
arch/mips/kernel/setup.c | 30 ++++++++++++++++++++++++++++++
|
||||||
|
1 file changed, 30 insertions(+)
|
||||||
|
|
||||||
|
--- a/arch/mips/kernel/setup.c
|
||||||
|
+++ b/arch/mips/kernel/setup.c
|
||||||
|
@@ -571,8 +571,28 @@ static int __init bootcmdline_scan_chose
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int __init bootcmdline_scan_chosen_override(unsigned long node, const char *uname,
|
||||||
|
+ int depth, void *data)
|
||||||
|
+{
|
||||||
|
+ bool *dt_bootargs = data;
|
||||||
|
+ const char *p;
|
||||||
|
+ int l;
|
||||||
|
+
|
||||||
|
+ if (depth != 1 || !data || strcmp(uname, "chosen") != 0)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ p = of_get_flat_dt_prop(node, "bootargs-override", &l);
|
||||||
|
+ if (p != NULL && l > 0) {
|
||||||
|
+ strlcpy(boot_command_line, p, COMMAND_LINE_SIZE);
|
||||||
|
+ *dt_bootargs = true;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 1;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void __init bootcmdline_init(char **cmdline_p)
|
||||||
|
{
|
||||||
|
+ bool dt_bootargs_override = false;
|
||||||
|
bool dt_bootargs = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -586,6 +606,14 @@ static void __init bootcmdline_init(char
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
+ * If bootargs-override in the chosen node is set, use this as the
|
||||||
|
+ * command line
|
||||||
|
+ */
|
||||||
|
+ of_scan_flat_dt(bootcmdline_scan_chosen_override, &dt_bootargs_override);
|
||||||
|
+ if (dt_bootargs_override)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
* If the user specified a built-in command line &
|
||||||
|
* MIPS_CMDLINE_BUILTIN_EXTEND, then the built-in command line is
|
||||||
|
* prepended to arguments from the bootloader or DT so we'll copy them
|
@ -0,0 +1,29 @@
|
|||||||
|
From 5ede027f6c4a57ed25da872420508b7f1168b36b Mon Sep 17 00:00:00 2001
|
||||||
|
From: John Crispin <blogic@openwrt.org>
|
||||||
|
Date: Mon, 7 Dec 2015 17:15:32 +0100
|
||||||
|
Subject: [PATCH 13/53] owrt: hack: fix mt7688 cache issue
|
||||||
|
|
||||||
|
Signed-off-by: John Crispin <blogic@openwrt.org>
|
||||||
|
---
|
||||||
|
arch/mips/kernel/setup.c | 2 +-
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
--- a/arch/mips/kernel/setup.c
|
||||||
|
+++ b/arch/mips/kernel/setup.c
|
||||||
|
@@ -723,8 +723,6 @@ static void __init arch_mem_init(char **
|
||||||
|
memblock_reserve(crashk_res.start,
|
||||||
|
crashk_res.end - crashk_res.start + 1);
|
||||||
|
#endif
|
||||||
|
- device_tree_init();
|
||||||
|
-
|
||||||
|
/*
|
||||||
|
* In order to reduce the possibility of kernel panic when failed to
|
||||||
|
* get IO TLB memory under CONFIG_SWIOTLB, it is better to allocate
|
||||||
|
@@ -841,6 +839,7 @@ void __init setup_arch(char **cmdline_p)
|
||||||
|
|
||||||
|
cpu_cache_init();
|
||||||
|
paging_init();
|
||||||
|
+ device_tree_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long kernelsp[NR_CPUS];
|
@ -0,0 +1,25 @@
|
|||||||
|
From 9e6ce539092a1dd605a20bf73c655a9de58d8641 Mon Sep 17 00:00:00 2001
|
||||||
|
From: John Crispin <blogic@openwrt.org>
|
||||||
|
Date: Mon, 7 Dec 2015 17:18:05 +0100
|
||||||
|
Subject: [PATCH 15/53] arch: mips: do not select illegal access driver by
|
||||||
|
default
|
||||||
|
|
||||||
|
Signed-off-by: John Crispin <blogic@openwrt.org>
|
||||||
|
---
|
||||||
|
arch/mips/ralink/Kconfig | 4 ++--
|
||||||
|
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
--- a/arch/mips/ralink/Kconfig
|
||||||
|
+++ b/arch/mips/ralink/Kconfig
|
||||||
|
@@ -14,9 +14,9 @@ config CLKEVT_RT3352
|
||||||
|
select CEVT_SYSTICK_QUIRK
|
||||||
|
|
||||||
|
config RALINK_ILL_ACC
|
||||||
|
- bool
|
||||||
|
+ bool "illegal access irq"
|
||||||
|
depends on SOC_RT305X
|
||||||
|
- default y
|
||||||
|
+ default n
|
||||||
|
|
||||||
|
config IRQ_INTC
|
||||||
|
bool
|
@ -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
|
||||||
|
@@ -563,7 +563,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;
|
||||||
|
@@ -625,6 +625,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,
|
||||||
|
@@ -646,6 +648,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)
|
||||||
|
{
|
@ -0,0 +1,59 @@
|
|||||||
|
From d410e5478c622c01fcf31427533df5f433df9146 Mon Sep 17 00:00:00 2001
|
||||||
|
From: John Crispin <blogic@openwrt.org>
|
||||||
|
Date: Sun, 28 Jul 2013 19:45:30 +0200
|
||||||
|
Subject: [PATCH 26/53] DT: Add documentation for gpio-ralink
|
||||||
|
|
||||||
|
Describe gpio-ralink binding.
|
||||||
|
|
||||||
|
Signed-off-by: John Crispin <blogic@openwrt.org>
|
||||||
|
Cc: linux-mips@linux-mips.org
|
||||||
|
Cc: devicetree@vger.kernel.org
|
||||||
|
Cc: linux-gpio@vger.kernel.org
|
||||||
|
---
|
||||||
|
.../devicetree/bindings/gpio/gpio-ralink.txt | 40 ++++++++++++++++++++
|
||||||
|
1 file changed, 40 insertions(+)
|
||||||
|
create mode 100644 Documentation/devicetree/bindings/gpio/gpio-ralink.txt
|
||||||
|
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/Documentation/devicetree/bindings/gpio/gpio-ralink.txt
|
||||||
|
@@ -0,0 +1,40 @@
|
||||||
|
+Ralink SoC GPIO controller bindings
|
||||||
|
+
|
||||||
|
+Required properties:
|
||||||
|
+- compatible:
|
||||||
|
+ - "ralink,rt2880-gpio" for Ralink controllers
|
||||||
|
+- #gpio-cells : Should be two.
|
||||||
|
+ - first cell is the pin number
|
||||||
|
+ - second cell is used to specify optional parameters (unused)
|
||||||
|
+- gpio-controller : Marks the device node as a GPIO controller
|
||||||
|
+- reg : Physical base address and length of the controller's registers
|
||||||
|
+- interrupt-parent: phandle to the INTC device node
|
||||||
|
+- interrupts : Specify the INTC interrupt number
|
||||||
|
+- ralink,num-gpios : Specify the number of GPIOs
|
||||||
|
+- ralink,register-map : The register layout depends on the GPIO bank and actual
|
||||||
|
+ SoC type. Register offsets need to be in this order.
|
||||||
|
+ [ INT, EDGE, RENA, FENA, DATA, DIR, POL, SET, RESET, TOGGLE ]
|
||||||
|
+
|
||||||
|
+Optional properties:
|
||||||
|
+- ralink,gpio-base : Specify the GPIO chips base number
|
||||||
|
+
|
||||||
|
+Example:
|
||||||
|
+
|
||||||
|
+ gpio0: gpio@600 {
|
||||||
|
+ compatible = "ralink,rt5350-gpio", "ralink,rt2880-gpio";
|
||||||
|
+
|
||||||
|
+ #gpio-cells = <2>;
|
||||||
|
+ gpio-controller;
|
||||||
|
+
|
||||||
|
+ reg = <0x600 0x34>;
|
||||||
|
+
|
||||||
|
+ interrupt-parent = <&intc>;
|
||||||
|
+ interrupts = <6>;
|
||||||
|
+
|
||||||
|
+ ralink,gpio-base = <0>;
|
||||||
|
+ ralink,num-gpios = <24>;
|
||||||
|
+ ralink,register-map = [ 00 04 08 0c
|
||||||
|
+ 20 24 28 2c
|
||||||
|
+ 30 34 ];
|
||||||
|
+
|
||||||
|
+ };
|
@ -0,0 +1,416 @@
|
|||||||
|
From 69fdd2c4f937796b934e89c33acde9d082e27bfd Mon Sep 17 00:00:00 2001
|
||||||
|
From: John Crispin <blogic@openwrt.org>
|
||||||
|
Date: Mon, 4 Aug 2014 20:36:29 +0200
|
||||||
|
Subject: [PATCH 27/53] GPIO: MIPS: ralink: add gpio driver for ralink SoC
|
||||||
|
|
||||||
|
Add gpio driver for Ralink SoC. This driver makes the gpio core on
|
||||||
|
RT2880, RT305x, rt3352, rt3662, rt3883, rt5350 and mt7620 work.
|
||||||
|
|
||||||
|
Signed-off-by: John Crispin <blogic@openwrt.org>
|
||||||
|
Cc: linux-mips@linux-mips.org
|
||||||
|
Cc: linux-gpio@vger.kernel.org
|
||||||
|
---
|
||||||
|
arch/mips/include/asm/mach-ralink/gpio.h | 24 ++
|
||||||
|
drivers/gpio/Kconfig | 6 +
|
||||||
|
drivers/gpio/Makefile | 1 +
|
||||||
|
drivers/gpio/gpio-ralink.c | 355 ++++++++++++++++++++++++++++++
|
||||||
|
4 files changed, 386 insertions(+)
|
||||||
|
create mode 100644 arch/mips/include/asm/mach-ralink/gpio.h
|
||||||
|
create mode 100644 drivers/gpio/gpio-ralink.c
|
||||||
|
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/mips/include/asm/mach-ralink/gpio.h
|
||||||
|
@@ -0,0 +1,24 @@
|
||||||
|
+/*
|
||||||
|
+ * Ralink SoC GPIO API support
|
||||||
|
+ *
|
||||||
|
+ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
|
||||||
|
+ *
|
||||||
|
+ * This program is free software; you can redistribute it and/or modify it
|
||||||
|
+ * under the terms of the GNU General Public License version 2 as published
|
||||||
|
+ * by the Free Software Foundation.
|
||||||
|
+ *
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#ifndef __ASM_MACH_RALINK_GPIO_H
|
||||||
|
+#define __ASM_MACH_RALINK_GPIO_H
|
||||||
|
+
|
||||||
|
+#define ARCH_NR_GPIOS 128
|
||||||
|
+#include <asm-generic/gpio.h>
|
||||||
|
+
|
||||||
|
+#define gpio_get_value __gpio_get_value
|
||||||
|
+#define gpio_set_value __gpio_set_value
|
||||||
|
+#define gpio_cansleep __gpio_cansleep
|
||||||
|
+#define gpio_to_irq __gpio_to_irq
|
||||||
|
+
|
||||||
|
+#endif /* __ASM_MACH_RALINK_GPIO_H */
|
||||||
|
--- a/drivers/gpio/Kconfig
|
||||||
|
+++ b/drivers/gpio/Kconfig
|
||||||
|
@@ -471,6 +471,12 @@ config GPIO_SNPS_CREG
|
||||||
|
where only several fields in register belong to GPIO lines and
|
||||||
|
each GPIO line owns a field with different length and on/off value.
|
||||||
|
|
||||||
|
+config GPIO_RALINK
|
||||||
|
+ bool "Ralink GPIO Support"
|
||||||
|
+ depends on RALINK
|
||||||
|
+ help
|
||||||
|
+ Say yes here to support the Ralink SoC GPIO device
|
||||||
|
+
|
||||||
|
config GPIO_SPEAR_SPICS
|
||||||
|
bool "ST SPEAr13xx SPI Chip Select as GPIO support"
|
||||||
|
depends on PLAT_SPEAR
|
||||||
|
--- a/drivers/gpio/Makefile
|
||||||
|
+++ b/drivers/gpio/Makefile
|
||||||
|
@@ -112,6 +112,7 @@ obj-$(CONFIG_GPIO_PISOSR) += gpio-pisos
|
||||||
|
obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
|
||||||
|
obj-$(CONFIG_GPIO_PMIC_EIC_SPRD) += gpio-pmic-eic-sprd.o
|
||||||
|
obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
|
||||||
|
+obj-$(CONFIG_GPIO_RALINK) += gpio-ralink.o
|
||||||
|
obj-$(CONFIG_GPIO_RASPBERRYPI_EXP) += gpio-raspberrypi-exp.o
|
||||||
|
obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
|
||||||
|
obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/drivers/gpio/gpio-ralink.c
|
||||||
|
@@ -0,0 +1,341 @@
|
||||||
|
+/*
|
||||||
|
+ * This program is free software; you can redistribute it and/or modify it
|
||||||
|
+ * under the terms of the GNU General Public License version 2 as published
|
||||||
|
+ * by the Free Software Foundation.
|
||||||
|
+ *
|
||||||
|
+ * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <linux/module.h>
|
||||||
|
+#include <linux/io.h>
|
||||||
|
+#include <linux/gpio.h>
|
||||||
|
+#include <linux/spinlock.h>
|
||||||
|
+#include <linux/platform_device.h>
|
||||||
|
+#include <linux/of_irq.h>
|
||||||
|
+#include <linux/irqdomain.h>
|
||||||
|
+#include <linux/interrupt.h>
|
||||||
|
+
|
||||||
|
+enum ralink_gpio_reg {
|
||||||
|
+ GPIO_REG_INT = 0,
|
||||||
|
+ GPIO_REG_EDGE,
|
||||||
|
+ GPIO_REG_RENA,
|
||||||
|
+ GPIO_REG_FENA,
|
||||||
|
+ GPIO_REG_DATA,
|
||||||
|
+ GPIO_REG_DIR,
|
||||||
|
+ GPIO_REG_POL,
|
||||||
|
+ GPIO_REG_SET,
|
||||||
|
+ GPIO_REG_RESET,
|
||||||
|
+ GPIO_REG_TOGGLE,
|
||||||
|
+ GPIO_REG_MAX
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+struct ralink_gpio_chip {
|
||||||
|
+ struct gpio_chip chip;
|
||||||
|
+ u8 regs[GPIO_REG_MAX];
|
||||||
|
+
|
||||||
|
+ spinlock_t lock;
|
||||||
|
+ void __iomem *membase;
|
||||||
|
+ struct irq_domain *domain;
|
||||||
|
+ int irq;
|
||||||
|
+
|
||||||
|
+ u32 rising;
|
||||||
|
+ u32 falling;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+#define MAP_MAX 4
|
||||||
|
+static struct irq_domain *irq_map[MAP_MAX];
|
||||||
|
+static int irq_map_count;
|
||||||
|
+static atomic_t irq_refcount = ATOMIC_INIT(0);
|
||||||
|
+
|
||||||
|
+static inline struct ralink_gpio_chip *to_ralink_gpio(struct gpio_chip *chip)
|
||||||
|
+{
|
||||||
|
+ struct ralink_gpio_chip *rg;
|
||||||
|
+
|
||||||
|
+ rg = container_of(chip, struct ralink_gpio_chip, chip);
|
||||||
|
+
|
||||||
|
+ return rg;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void rt_gpio_w32(struct ralink_gpio_chip *rg, u8 reg, u32 val)
|
||||||
|
+{
|
||||||
|
+ iowrite32(val, rg->membase + rg->regs[reg]);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline u32 rt_gpio_r32(struct ralink_gpio_chip *rg, u8 reg)
|
||||||
|
+{
|
||||||
|
+ return ioread32(rg->membase + rg->regs[reg]);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void ralink_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||||
|
+{
|
||||||
|
+ struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
|
||||||
|
+
|
||||||
|
+ rt_gpio_w32(rg, (value) ? GPIO_REG_SET : GPIO_REG_RESET, BIT(offset));
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ralink_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||||
|
+{
|
||||||
|
+ struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
|
||||||
|
+
|
||||||
|
+ return !!(rt_gpio_r32(rg, GPIO_REG_DATA) & BIT(offset));
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ralink_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||||
|
+{
|
||||||
|
+ struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
|
||||||
|
+ unsigned long flags;
|
||||||
|
+ u32 t;
|
||||||
|
+
|
||||||
|
+ spin_lock_irqsave(&rg->lock, flags);
|
||||||
|
+ t = rt_gpio_r32(rg, GPIO_REG_DIR);
|
||||||
|
+ t &= ~BIT(offset);
|
||||||
|
+ rt_gpio_w32(rg, GPIO_REG_DIR, t);
|
||||||
|
+ spin_unlock_irqrestore(&rg->lock, flags);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ralink_gpio_direction_output(struct gpio_chip *chip,
|
||||||
|
+ unsigned offset, int value)
|
||||||
|
+{
|
||||||
|
+ struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
|
||||||
|
+ unsigned long flags;
|
||||||
|
+ u32 t;
|
||||||
|
+
|
||||||
|
+ spin_lock_irqsave(&rg->lock, flags);
|
||||||
|
+ ralink_gpio_set(chip, offset, value);
|
||||||
|
+ t = rt_gpio_r32(rg, GPIO_REG_DIR);
|
||||||
|
+ t |= BIT(offset);
|
||||||
|
+ rt_gpio_w32(rg, GPIO_REG_DIR, t);
|
||||||
|
+ spin_unlock_irqrestore(&rg->lock, flags);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ralink_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
|
||||||
|
+{
|
||||||
|
+ struct ralink_gpio_chip *rg = to_ralink_gpio(chip);
|
||||||
|
+
|
||||||
|
+ if (rg->irq < 1)
|
||||||
|
+ return -1;
|
||||||
|
+
|
||||||
|
+ return irq_create_mapping(rg->domain, pin);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void ralink_gpio_irq_handler(struct irq_desc *desc)
|
||||||
|
+{
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < irq_map_count; i++) {
|
||||||
|
+ struct irq_domain *domain = irq_map[i];
|
||||||
|
+ struct ralink_gpio_chip *rg;
|
||||||
|
+ unsigned long pending;
|
||||||
|
+ int bit;
|
||||||
|
+
|
||||||
|
+ rg = (struct ralink_gpio_chip *) domain->host_data;
|
||||||
|
+ pending = rt_gpio_r32(rg, GPIO_REG_INT);
|
||||||
|
+
|
||||||
|
+ for_each_set_bit(bit, &pending, rg->chip.ngpio) {
|
||||||
|
+ u32 map = irq_find_mapping(domain, bit);
|
||||||
|
+ generic_handle_irq(map);
|
||||||
|
+ rt_gpio_w32(rg, GPIO_REG_INT, BIT(bit));
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void ralink_gpio_irq_unmask(struct irq_data *d)
|
||||||
|
+{
|
||||||
|
+ struct ralink_gpio_chip *rg;
|
||||||
|
+ unsigned long flags;
|
||||||
|
+ u32 rise, fall;
|
||||||
|
+
|
||||||
|
+ rg = (struct ralink_gpio_chip *) d->domain->host_data;
|
||||||
|
+ rise = rt_gpio_r32(rg, GPIO_REG_RENA);
|
||||||
|
+ fall = rt_gpio_r32(rg, GPIO_REG_FENA);
|
||||||
|
+
|
||||||
|
+ spin_lock_irqsave(&rg->lock, flags);
|
||||||
|
+ rt_gpio_w32(rg, GPIO_REG_RENA, rise | (BIT(d->hwirq) & rg->rising));
|
||||||
|
+ rt_gpio_w32(rg, GPIO_REG_FENA, fall | (BIT(d->hwirq) & rg->falling));
|
||||||
|
+ spin_unlock_irqrestore(&rg->lock, flags);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void ralink_gpio_irq_mask(struct irq_data *d)
|
||||||
|
+{
|
||||||
|
+ struct ralink_gpio_chip *rg;
|
||||||
|
+ unsigned long flags;
|
||||||
|
+ u32 rise, fall;
|
||||||
|
+
|
||||||
|
+ rg = (struct ralink_gpio_chip *) d->domain->host_data;
|
||||||
|
+ rise = rt_gpio_r32(rg, GPIO_REG_RENA);
|
||||||
|
+ fall = rt_gpio_r32(rg, GPIO_REG_FENA);
|
||||||
|
+
|
||||||
|
+ spin_lock_irqsave(&rg->lock, flags);
|
||||||
|
+ rt_gpio_w32(rg, GPIO_REG_FENA, fall & ~BIT(d->hwirq));
|
||||||
|
+ rt_gpio_w32(rg, GPIO_REG_RENA, rise & ~BIT(d->hwirq));
|
||||||
|
+ spin_unlock_irqrestore(&rg->lock, flags);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ralink_gpio_irq_type(struct irq_data *d, unsigned int type)
|
||||||
|
+{
|
||||||
|
+ struct ralink_gpio_chip *rg;
|
||||||
|
+ u32 mask = BIT(d->hwirq);
|
||||||
|
+
|
||||||
|
+ rg = (struct ralink_gpio_chip *) d->domain->host_data;
|
||||||
|
+
|
||||||
|
+ if (type == IRQ_TYPE_PROBE) {
|
||||||
|
+ if ((rg->rising | rg->falling) & mask)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (type & IRQ_TYPE_EDGE_RISING)
|
||||||
|
+ rg->rising |= mask;
|
||||||
|
+ else
|
||||||
|
+ rg->rising &= ~mask;
|
||||||
|
+
|
||||||
|
+ if (type & IRQ_TYPE_EDGE_FALLING)
|
||||||
|
+ rg->falling |= mask;
|
||||||
|
+ else
|
||||||
|
+ rg->falling &= ~mask;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static struct irq_chip ralink_gpio_irq_chip = {
|
||||||
|
+ .name = "GPIO",
|
||||||
|
+ .irq_unmask = ralink_gpio_irq_unmask,
|
||||||
|
+ .irq_mask = ralink_gpio_irq_mask,
|
||||||
|
+ .irq_mask_ack = ralink_gpio_irq_mask,
|
||||||
|
+ .irq_set_type = ralink_gpio_irq_type,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static int gpio_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
|
||||||
|
+{
|
||||||
|
+ irq_set_chip_and_handler(irq, &ralink_gpio_irq_chip, handle_level_irq);
|
||||||
|
+ irq_set_handler_data(irq, d);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static const struct irq_domain_ops irq_domain_ops = {
|
||||||
|
+ .xlate = irq_domain_xlate_onecell,
|
||||||
|
+ .map = gpio_map,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static void ralink_gpio_irq_init(struct device_node *np,
|
||||||
|
+ struct ralink_gpio_chip *rg)
|
||||||
|
+{
|
||||||
|
+ if (irq_map_count >= MAP_MAX)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ rg->irq = irq_of_parse_and_map(np, 0);
|
||||||
|
+ if (!rg->irq)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ rg->domain = irq_domain_add_linear(np, rg->chip.ngpio,
|
||||||
|
+ &irq_domain_ops, rg);
|
||||||
|
+ if (!rg->domain) {
|
||||||
|
+ dev_err(rg->chip.parent, "irq_domain_add_linear failed\n");
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ irq_map[irq_map_count++] = rg->domain;
|
||||||
|
+
|
||||||
|
+ rt_gpio_w32(rg, GPIO_REG_RENA, 0x0);
|
||||||
|
+ rt_gpio_w32(rg, GPIO_REG_FENA, 0x0);
|
||||||
|
+
|
||||||
|
+ if (!atomic_read(&irq_refcount))
|
||||||
|
+ irq_set_chained_handler(rg->irq, ralink_gpio_irq_handler);
|
||||||
|
+ atomic_inc(&irq_refcount);
|
||||||
|
+
|
||||||
|
+ dev_info(rg->chip.parent, "registering %d irq handlers\n", rg->chip.ngpio);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ralink_gpio_probe(struct platform_device *pdev)
|
||||||
|
+{
|
||||||
|
+ struct device_node *np = pdev->dev.of_node;
|
||||||
|
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
+ struct ralink_gpio_chip *rg;
|
||||||
|
+ const __be32 *ngpio, *gpiobase;
|
||||||
|
+
|
||||||
|
+ if (!res) {
|
||||||
|
+ dev_err(&pdev->dev, "failed to find resource\n");
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ rg = devm_kzalloc(&pdev->dev,
|
||||||
|
+ sizeof(struct ralink_gpio_chip), GFP_KERNEL);
|
||||||
|
+ if (!rg)
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+
|
||||||
|
+ rg->membase = devm_ioremap_resource(&pdev->dev, res);
|
||||||
|
+ if (!rg->membase) {
|
||||||
|
+ dev_err(&pdev->dev, "cannot remap I/O memory region\n");
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (of_property_read_u8_array(np, "ralink,register-map",
|
||||||
|
+ rg->regs, GPIO_REG_MAX)) {
|
||||||
|
+ dev_err(&pdev->dev, "failed to read register definition\n");
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ngpio = of_get_property(np, "ralink,num-gpios", NULL);
|
||||||
|
+ if (!ngpio) {
|
||||||
|
+ dev_err(&pdev->dev, "failed to read number of pins\n");
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ gpiobase = of_get_property(np, "ralink,gpio-base", NULL);
|
||||||
|
+ if (gpiobase)
|
||||||
|
+ rg->chip.base = be32_to_cpu(*gpiobase);
|
||||||
|
+ else
|
||||||
|
+ rg->chip.base = -1;
|
||||||
|
+
|
||||||
|
+ spin_lock_init(&rg->lock);
|
||||||
|
+
|
||||||
|
+ rg->chip.parent = &pdev->dev;
|
||||||
|
+ rg->chip.label = dev_name(&pdev->dev);
|
||||||
|
+ rg->chip.of_node = np;
|
||||||
|
+ rg->chip.ngpio = be32_to_cpu(*ngpio);
|
||||||
|
+ rg->chip.direction_input = ralink_gpio_direction_input;
|
||||||
|
+ rg->chip.direction_output = ralink_gpio_direction_output;
|
||||||
|
+ rg->chip.get = ralink_gpio_get;
|
||||||
|
+ rg->chip.set = ralink_gpio_set;
|
||||||
|
+ rg->chip.request = gpiochip_generic_request;
|
||||||
|
+ rg->chip.to_irq = ralink_gpio_to_irq;
|
||||||
|
+ rg->chip.free = gpiochip_generic_free;
|
||||||
|
+
|
||||||
|
+ /* set polarity to low for all lines */
|
||||||
|
+ rt_gpio_w32(rg, GPIO_REG_POL, 0);
|
||||||
|
+
|
||||||
|
+ dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio);
|
||||||
|
+
|
||||||
|
+ ralink_gpio_irq_init(np, rg);
|
||||||
|
+
|
||||||
|
+ return gpiochip_add(&rg->chip);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static const struct of_device_id ralink_gpio_match[] = {
|
||||||
|
+ { .compatible = "ralink,rt2880-gpio" },
|
||||||
|
+ {},
|
||||||
|
+};
|
||||||
|
+MODULE_DEVICE_TABLE(of, ralink_gpio_match);
|
||||||
|
+
|
||||||
|
+static struct platform_driver ralink_gpio_driver = {
|
||||||
|
+ .probe = ralink_gpio_probe,
|
||||||
|
+ .driver = {
|
||||||
|
+ .name = "rt2880_gpio",
|
||||||
|
+ .owner = THIS_MODULE,
|
||||||
|
+ .of_match_table = ralink_gpio_match,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static int __init ralink_gpio_init(void)
|
||||||
|
+{
|
||||||
|
+ return platform_driver_register(&ralink_gpio_driver);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+subsys_initcall(ralink_gpio_init);
|
@ -0,0 +1,44 @@
|
|||||||
|
From 57fa7f2f4ef6f78ce1d30509c0d111aa3791b524 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Daniel Santos <daniel.santos@pobox.com>
|
||||||
|
Date: Sun, 4 Nov 2018 20:24:32 -0600
|
||||||
|
Subject: gpio-ralink: Add support for GPIO as interrupt-controller
|
||||||
|
|
||||||
|
Signed-off-by: Daniel Santos <daniel.santos@pobox.com>
|
||||||
|
---
|
||||||
|
Documentation/devicetree/bindings/gpio/gpio-ralink.txt | 6 ++++++
|
||||||
|
drivers/gpio/gpio-ralink.c | 2 +-
|
||||||
|
2 files changed, 7 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
--- a/Documentation/devicetree/bindings/gpio/gpio-ralink.txt
|
||||||
|
+++ b/Documentation/devicetree/bindings/gpio/gpio-ralink.txt
|
||||||
|
@@ -17,6 +17,9 @@ Required properties:
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- ralink,gpio-base : Specify the GPIO chips base number
|
||||||
|
+- interrupt-controller : marks this as an interrupt controller
|
||||||
|
+- #interrupt-cells : a standard two-cell interrupt flag, see
|
||||||
|
+ interrupt-controller/interrupts.txt
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
@@ -28,6 +31,9 @@ Example:
|
||||||
|
|
||||||
|
reg = <0x600 0x34>;
|
||||||
|
|
||||||
|
+ interrupt-controller;
|
||||||
|
+ #interrupt-cells = <2>;
|
||||||
|
+
|
||||||
|
interrupt-parent = <&intc>;
|
||||||
|
interrupts = <6>;
|
||||||
|
|
||||||
|
--- a/drivers/gpio/gpio-ralink.c
|
||||||
|
+++ b/drivers/gpio/gpio-ralink.c
|
||||||
|
@@ -220,7 +220,7 @@ static int gpio_map(struct irq_domain *d
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct irq_domain_ops irq_domain_ops = {
|
||||||
|
- .xlate = irq_domain_xlate_onecell,
|
||||||
|
+ .xlate = irq_domain_xlate_twocell,
|
||||||
|
.map = gpio_map,
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,246 @@
|
|||||||
|
From 975e76214cd2516eb6cfff4c3eec581872645e88 Mon Sep 17 00:00:00 2001
|
||||||
|
From: John Crispin <blogic@openwrt.org>
|
||||||
|
Date: Thu, 19 Sep 2013 01:50:59 +0200
|
||||||
|
Subject: [PATCH 31/53] uvc: add iPassion iP2970 support
|
||||||
|
|
||||||
|
Signed-off-by: John Crispin <blogic@openwrt.org>
|
||||||
|
---
|
||||||
|
drivers/media/usb/uvc/uvc_driver.c | 12 +++
|
||||||
|
drivers/media/usb/uvc/uvc_status.c | 2 +
|
||||||
|
drivers/media/usb/uvc/uvc_video.c | 147 ++++++++++++++++++++++++++++++++++++
|
||||||
|
drivers/media/usb/uvc/uvcvideo.h | 5 +-
|
||||||
|
4 files changed, 165 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
--- a/drivers/media/usb/uvc/uvc_driver.c
|
||||||
|
+++ b/drivers/media/usb/uvc/uvc_driver.c
|
||||||
|
@@ -2908,6 +2908,18 @@ static const struct usb_device_id uvc_id
|
||||||
|
.bInterfaceSubClass = 1,
|
||||||
|
.bInterfaceProtocol = 0,
|
||||||
|
.driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) },
|
||||||
|
+ /* iPassion iP2970 */
|
||||||
|
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
|
||||||
|
+ | USB_DEVICE_ID_MATCH_INT_INFO,
|
||||||
|
+ .idVendor = 0x1B3B,
|
||||||
|
+ .idProduct = 0x2970,
|
||||||
|
+ .bInterfaceClass = USB_CLASS_VIDEO,
|
||||||
|
+ .bInterfaceSubClass = 1,
|
||||||
|
+ .bInterfaceProtocol = 0,
|
||||||
|
+ .driver_info = UVC_QUIRK_PROBE_MINMAX
|
||||||
|
+ | UVC_QUIRK_STREAM_NO_FID
|
||||||
|
+ | UVC_QUIRK_MOTION
|
||||||
|
+ | UVC_QUIRK_SINGLE_ISO },
|
||||||
|
/* Generic USB Video Class */
|
||||||
|
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) },
|
||||||
|
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_15) },
|
||||||
|
--- a/drivers/media/usb/uvc/uvc_status.c
|
||||||
|
+++ b/drivers/media/usb/uvc/uvc_status.c
|
||||||
|
@@ -223,6 +223,7 @@ static void uvc_status_complete(struct u
|
||||||
|
if (uvc_event_control(urb, status, len))
|
||||||
|
/* The URB will be resubmitted in work context. */
|
||||||
|
return;
|
||||||
|
+ dev->motion = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -271,6 +272,7 @@ int uvc_status_init(struct uvc_device *d
|
||||||
|
}
|
||||||
|
|
||||||
|
pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress);
|
||||||
|
+ dev->motion = 0;
|
||||||
|
|
||||||
|
/* For high-speed interrupt endpoints, the bInterval value is used as
|
||||||
|
* an exponent of two. Some developers forgot about it.
|
||||||
|
--- a/drivers/media/usb/uvc/uvc_video.c
|
||||||
|
+++ b/drivers/media/usb/uvc/uvc_video.c
|
||||||
|
@@ -16,6 +16,11 @@
|
||||||
|
#include <linux/wait.h>
|
||||||
|
#include <linux/atomic.h>
|
||||||
|
#include <asm/unaligned.h>
|
||||||
|
+#include <linux/skbuff.h>
|
||||||
|
+#include <linux/kobject.h>
|
||||||
|
+#include <linux/netlink.h>
|
||||||
|
+#include <linux/kobject.h>
|
||||||
|
+#include <linux/workqueue.h>
|
||||||
|
|
||||||
|
#include <media/v4l2-common.h>
|
||||||
|
|
||||||
|
@@ -1156,9 +1161,149 @@ static void uvc_video_decode_data(struct
|
||||||
|
uvc_urb->async_operations++;
|
||||||
|
}
|
||||||
|
|
||||||
|
+struct bh_priv {
|
||||||
|
+ unsigned long seen;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+struct bh_event {
|
||||||
|
+ const char *name;
|
||||||
|
+ struct sk_buff *skb;
|
||||||
|
+ struct work_struct work;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+#define BH_ERR(fmt, args...) printk(KERN_ERR "%s: " fmt, "webcam", ##args )
|
||||||
|
+#define BH_DBG(fmt, args...) do {} while (0)
|
||||||
|
+#define BH_SKB_SIZE 2048
|
||||||
|
+
|
||||||
|
+extern u64 uevent_next_seqnum(void);
|
||||||
|
+static int seen = 0;
|
||||||
|
+
|
||||||
|
+static int bh_event_add_var(struct bh_event *event, int argv,
|
||||||
|
+ const char *format, ...)
|
||||||
|
+{
|
||||||
|
+ static char buf[128];
|
||||||
|
+ char *s;
|
||||||
|
+ va_list args;
|
||||||
|
+ int len;
|
||||||
|
+
|
||||||
|
+ if (argv)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ va_start(args, format);
|
||||||
|
+ len = vsnprintf(buf, sizeof(buf), format, args);
|
||||||
|
+ va_end(args);
|
||||||
|
+
|
||||||
|
+ if (len >= sizeof(buf)) {
|
||||||
|
+ BH_ERR("buffer size too small\n");
|
||||||
|
+ WARN_ON(1);
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ s = skb_put(event->skb, len + 1);
|
||||||
|
+ strcpy(s, buf);
|
||||||
|
+
|
||||||
|
+ BH_DBG("added variable '%s'\n", s);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int motion_hotplug_fill_event(struct bh_event *event)
|
||||||
|
+{
|
||||||
|
+ int s = jiffies;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ if (!seen)
|
||||||
|
+ seen = jiffies;
|
||||||
|
+
|
||||||
|
+ ret = bh_event_add_var(event, 0, "HOME=%s", "/");
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
+ ret = bh_event_add_var(event, 0, "PATH=%s",
|
||||||
|
+ "/sbin:/bin:/usr/sbin:/usr/bin");
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
+ ret = bh_event_add_var(event, 0, "SUBSYSTEM=usb");
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
+ ret = bh_event_add_var(event, 0, "ACTION=motion");
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
+ ret = bh_event_add_var(event, 0, "SEEN=%d", s - seen);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+ seen = s;
|
||||||
|
+
|
||||||
|
+ ret = bh_event_add_var(event, 0, "SEQNUM=%llu", uevent_next_seqnum());
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void motion_hotplug_work(struct work_struct *work)
|
||||||
|
+{
|
||||||
|
+ struct bh_event *event = container_of(work, struct bh_event, work);
|
||||||
|
+ int ret = 0;
|
||||||
|
+
|
||||||
|
+ event->skb = alloc_skb(BH_SKB_SIZE, GFP_KERNEL);
|
||||||
|
+ if (!event->skb)
|
||||||
|
+ goto out_free_event;
|
||||||
|
+
|
||||||
|
+ ret = bh_event_add_var(event, 0, "%s@", "add");
|
||||||
|
+ if (ret)
|
||||||
|
+ goto out_free_skb;
|
||||||
|
+
|
||||||
|
+ ret = motion_hotplug_fill_event(event);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto out_free_skb;
|
||||||
|
+
|
||||||
|
+ NETLINK_CB(event->skb).dst_group = 1;
|
||||||
|
+ broadcast_uevent(event->skb, 0, 1, GFP_KERNEL);
|
||||||
|
+
|
||||||
|
+out_free_skb:
|
||||||
|
+ if (ret) {
|
||||||
|
+ BH_ERR("work error %d\n", ret);
|
||||||
|
+ kfree_skb(event->skb);
|
||||||
|
+ }
|
||||||
|
+out_free_event:
|
||||||
|
+ kfree(event);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int motion_hotplug_create_event(void)
|
||||||
|
+{
|
||||||
|
+ struct bh_event *event;
|
||||||
|
+
|
||||||
|
+ event = kzalloc(sizeof(*event), GFP_KERNEL);
|
||||||
|
+ if (!event)
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+
|
||||||
|
+ event->name = "motion";
|
||||||
|
+
|
||||||
|
+ INIT_WORK(&event->work, (void *)(void *)motion_hotplug_work);
|
||||||
|
+ schedule_work(&event->work);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#define MOTION_FLAG_OFFSET 4
|
||||||
|
static void uvc_video_decode_end(struct uvc_streaming *stream,
|
||||||
|
struct uvc_buffer *buf, const u8 *data, int len)
|
||||||
|
{
|
||||||
|
+ if ((stream->dev->quirks & UVC_QUIRK_MOTION) &&
|
||||||
|
+ (data[len - 2] == 0xff) && (data[len - 1] == 0xd9)) {
|
||||||
|
+ u8 *mem;
|
||||||
|
+ buf->state = UVC_BUF_STATE_READY;
|
||||||
|
+ mem = (u8 *) (buf->mem + MOTION_FLAG_OFFSET);
|
||||||
|
+ if ( stream->dev->motion ) {
|
||||||
|
+ stream->dev->motion = 0;
|
||||||
|
+ motion_hotplug_create_event();
|
||||||
|
+ } else {
|
||||||
|
+ *mem &= 0x7f;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
/* Mark the buffer as done if the EOF marker is set. */
|
||||||
|
if (data[1] & UVC_STREAM_EOF && buf->bytesused != 0) {
|
||||||
|
uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n");
|
||||||
|
@@ -1715,6 +1860,8 @@ static int uvc_init_video_isoc(struct uv
|
||||||
|
if (npackets == 0)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
+ if (stream->dev->quirks & UVC_QUIRK_SINGLE_ISO)
|
||||||
|
+ npackets = 1;
|
||||||
|
size = npackets * psize;
|
||||||
|
|
||||||
|
for_each_uvc_urb(uvc_urb, stream) {
|
||||||
|
--- a/drivers/media/usb/uvc/uvcvideo.h
|
||||||
|
+++ b/drivers/media/usb/uvc/uvcvideo.h
|
||||||
|
@@ -199,7 +199,9 @@
|
||||||
|
#define UVC_QUIRK_RESTORE_CTRLS_ON_INIT 0x00000400
|
||||||
|
#define UVC_QUIRK_FORCE_Y8 0x00000800
|
||||||
|
#define UVC_QUIRK_FORCE_BPP 0x00001000
|
||||||
|
-
|
||||||
|
+#define UVC_QUIRK_MOTION 0x00001000
|
||||||
|
+#define UVC_QUIRK_SINGLE_ISO 0x00002000
|
||||||
|
+
|
||||||
|
/* Format flags */
|
||||||
|
#define UVC_FMT_FLAG_COMPRESSED 0x00000001
|
||||||
|
#define UVC_FMT_FLAG_STREAM 0x00000002
|
||||||
|
@@ -666,6 +668,7 @@ struct uvc_device {
|
||||||
|
u8 *status;
|
||||||
|
struct input_dev *input;
|
||||||
|
char input_phys[64];
|
||||||
|
+ int motion;
|
||||||
|
|
||||||
|
struct uvc_ctrl_work {
|
||||||
|
struct work_struct work;
|
@ -0,0 +1,20 @@
|
|||||||
|
From ee9081b2726a5ca8cde5497afdc5425e21ff8f8b Mon Sep 17 00:00:00 2001
|
||||||
|
From: John Crispin <blogic@openwrt.org>
|
||||||
|
Date: Mon, 15 Jul 2013 00:39:21 +0200
|
||||||
|
Subject: [PATCH 37/53] mtd: cfi cmdset 0002 force word write
|
||||||
|
|
||||||
|
---
|
||||||
|
drivers/mtd/chips/cfi_cmdset_0002.c | 9 +++++++--
|
||||||
|
1 file changed, 7 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
|
||||||
|
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
|
||||||
|
@@ -40,7 +40,7 @@
|
||||||
|
#include <linux/mtd/xip.h>
|
||||||
|
|
||||||
|
#define AMD_BOOTLOC_BUG
|
||||||
|
-#define FORCE_WORD_WRITE 0
|
||||||
|
+#define FORCE_WORD_WRITE 1
|
||||||
|
|
||||||
|
#define MAX_RETRIES 3
|
||||||
|
|
@ -0,0 +1,44 @@
|
|||||||
|
From da6015e7f19d749f135f7ac55c4ec47b06faa868 Mon Sep 17 00:00:00 2001
|
||||||
|
From: John Crispin <blogic@openwrt.org>
|
||||||
|
Date: Fri, 9 Aug 2013 20:12:59 +0200
|
||||||
|
Subject: [PATCH 41/53] DT: Add documentation for spi-rt2880
|
||||||
|
|
||||||
|
Describe the SPI master found on the MIPS based Ralink RT2880 SoC.
|
||||||
|
|
||||||
|
Signed-off-by: John Crispin <blogic@openwrt.org>
|
||||||
|
---
|
||||||
|
.../devicetree/bindings/spi/spi-rt2880.txt | 28 ++++++++++++++++++++
|
||||||
|
1 file changed, 28 insertions(+)
|
||||||
|
create mode 100644 Documentation/devicetree/bindings/spi/spi-rt2880.txt
|
||||||
|
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/Documentation/devicetree/bindings/spi/spi-rt2880.txt
|
||||||
|
@@ -0,0 +1,28 @@
|
||||||
|
+Ralink SoC RT2880 SPI master controller.
|
||||||
|
+
|
||||||
|
+This SPI controller is found on most wireless SoCs made by ralink.
|
||||||
|
+
|
||||||
|
+Required properties:
|
||||||
|
+- compatible : "ralink,rt2880-spi"
|
||||||
|
+- reg : The register base for the controller.
|
||||||
|
+- #address-cells : <1>, as required by generic SPI binding.
|
||||||
|
+- #size-cells : <0>, also as required by generic SPI binding.
|
||||||
|
+
|
||||||
|
+Child nodes as per the generic SPI binding.
|
||||||
|
+
|
||||||
|
+Example:
|
||||||
|
+
|
||||||
|
+ spi@b00 {
|
||||||
|
+ compatible = "ralink,rt2880-spi";
|
||||||
|
+ reg = <0xb00 0x100>;
|
||||||
|
+
|
||||||
|
+ #address-cells = <1>;
|
||||||
|
+ #size-cells = <0>;
|
||||||
|
+
|
||||||
|
+ m25p80@0 {
|
||||||
|
+ compatible = "m25p80";
|
||||||
|
+ reg = <0>;
|
||||||
|
+ spi-max-frequency = <10000000>;
|
||||||
|
+ };
|
||||||
|
+ };
|
||||||
|
+
|
@ -0,0 +1,574 @@
|
|||||||
|
From 683af4ebb91a1600df1946ac4769d916b8a1be65 Mon Sep 17 00:00:00 2001
|
||||||
|
From: John Crispin <blogic@openwrt.org>
|
||||||
|
Date: Sun, 27 Jul 2014 11:15:12 +0100
|
||||||
|
Subject: [PATCH 42/53] SPI: ralink: add Ralink SoC spi driver
|
||||||
|
|
||||||
|
Add the driver needed to make SPI work on Ralink SoC.
|
||||||
|
|
||||||
|
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
Acked-by: John Crispin <blogic@openwrt.org>
|
||||||
|
---
|
||||||
|
drivers/spi/Kconfig | 6 +
|
||||||
|
drivers/spi/Makefile | 1 +
|
||||||
|
drivers/spi/spi-rt2880.c | 530 ++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
3 files changed, 537 insertions(+)
|
||||||
|
create mode 100644 drivers/spi/spi-rt2880.c
|
||||||
|
|
||||||
|
--- a/drivers/spi/Kconfig
|
||||||
|
+++ b/drivers/spi/Kconfig
|
||||||
|
@@ -605,6 +605,12 @@ config SPI_QCOM_GENI
|
||||||
|
This driver can also be built as a module. If so, the module
|
||||||
|
will be called spi-geni-qcom.
|
||||||
|
|
||||||
|
+config SPI_RT2880
|
||||||
|
+ tristate "Ralink RT288x SPI Controller"
|
||||||
|
+ depends on RALINK
|
||||||
|
+ help
|
||||||
|
+ This selects a driver for the Ralink RT288x/RT305x SPI Controller.
|
||||||
|
+
|
||||||
|
config SPI_S3C24XX
|
||||||
|
tristate "Samsung S3C24XX series SPI"
|
||||||
|
depends on ARCH_S3C24XX
|
||||||
|
--- a/drivers/spi/Makefile
|
||||||
|
+++ b/drivers/spi/Makefile
|
||||||
|
@@ -87,6 +87,7 @@ obj-$(CONFIG_SPI_QUP) += spi-qup.o
|
||||||
|
obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o
|
||||||
|
obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o
|
||||||
|
obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
|
||||||
|
+obj-$(CONFIG_SPI_RT2880) += spi-rt2880.o
|
||||||
|
obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
|
||||||
|
spi-s3c24xx-hw-y := spi-s3c24xx.o
|
||||||
|
spi-s3c24xx-hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi-s3c24xx-fiq.o
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/drivers/spi/spi-rt2880.c
|
||||||
|
@@ -0,0 +1,530 @@
|
||||||
|
+/*
|
||||||
|
+ * spi-rt2880.c -- Ralink RT288x/RT305x SPI controller driver
|
||||||
|
+ *
|
||||||
|
+ * Copyright (C) 2011 Sergiy <piratfm@gmail.com>
|
||||||
|
+ * Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
+ *
|
||||||
|
+ * Some parts are based on spi-orion.c:
|
||||||
|
+ * Author: Shadi Ammouri <shadi@marvell.com>
|
||||||
|
+ * Copyright (C) 2007-2008 Marvell Ltd.
|
||||||
|
+ *
|
||||||
|
+ * This program is free software; you can redistribute it and/or modify
|
||||||
|
+ * it under the terms of the GNU General Public License version 2 as
|
||||||
|
+ * published by the Free Software Foundation.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <linux/init.h>
|
||||||
|
+#include <linux/module.h>
|
||||||
|
+#include <linux/clk.h>
|
||||||
|
+#include <linux/err.h>
|
||||||
|
+#include <linux/delay.h>
|
||||||
|
+#include <linux/io.h>
|
||||||
|
+#include <linux/reset.h>
|
||||||
|
+#include <linux/spi/spi.h>
|
||||||
|
+#include <linux/platform_device.h>
|
||||||
|
+#include <linux/gpio.h>
|
||||||
|
+
|
||||||
|
+#define DRIVER_NAME "spi-rt2880"
|
||||||
|
+
|
||||||
|
+#define RAMIPS_SPI_STAT 0x00
|
||||||
|
+#define RAMIPS_SPI_CFG 0x10
|
||||||
|
+#define RAMIPS_SPI_CTL 0x14
|
||||||
|
+#define RAMIPS_SPI_DATA 0x20
|
||||||
|
+#define RAMIPS_SPI_ADDR 0x24
|
||||||
|
+#define RAMIPS_SPI_BS 0x28
|
||||||
|
+#define RAMIPS_SPI_USER 0x2C
|
||||||
|
+#define RAMIPS_SPI_TXFIFO 0x30
|
||||||
|
+#define RAMIPS_SPI_RXFIFO 0x34
|
||||||
|
+#define RAMIPS_SPI_FIFO_STAT 0x38
|
||||||
|
+#define RAMIPS_SPI_MODE 0x3C
|
||||||
|
+#define RAMIPS_SPI_DEV_OFFSET 0x40
|
||||||
|
+#define RAMIPS_SPI_DMA 0x80
|
||||||
|
+#define RAMIPS_SPI_DMASTAT 0x84
|
||||||
|
+#define RAMIPS_SPI_ARBITER 0xF0
|
||||||
|
+
|
||||||
|
+/* SPISTAT register bit field */
|
||||||
|
+#define SPISTAT_BUSY BIT(0)
|
||||||
|
+
|
||||||
|
+/* SPICFG register bit field */
|
||||||
|
+#define SPICFG_ADDRMODE BIT(12)
|
||||||
|
+#define SPICFG_RXENVDIS BIT(11)
|
||||||
|
+#define SPICFG_RXCAP BIT(10)
|
||||||
|
+#define SPICFG_SPIENMODE BIT(9)
|
||||||
|
+#define SPICFG_MSBFIRST BIT(8)
|
||||||
|
+#define SPICFG_SPICLKPOL BIT(6)
|
||||||
|
+#define SPICFG_RXCLKEDGE_FALLING BIT(5)
|
||||||
|
+#define SPICFG_TXCLKEDGE_FALLING BIT(4)
|
||||||
|
+#define SPICFG_HIZSPI BIT(3)
|
||||||
|
+#define SPICFG_SPICLK_PRESCALE_MASK 0x7
|
||||||
|
+#define SPICFG_SPICLK_DIV2 0
|
||||||
|
+#define SPICFG_SPICLK_DIV4 1
|
||||||
|
+#define SPICFG_SPICLK_DIV8 2
|
||||||
|
+#define SPICFG_SPICLK_DIV16 3
|
||||||
|
+#define SPICFG_SPICLK_DIV32 4
|
||||||
|
+#define SPICFG_SPICLK_DIV64 5
|
||||||
|
+#define SPICFG_SPICLK_DIV128 6
|
||||||
|
+#define SPICFG_SPICLK_DISABLE 7
|
||||||
|
+
|
||||||
|
+/* SPICTL register bit field */
|
||||||
|
+#define SPICTL_START BIT(4)
|
||||||
|
+#define SPICTL_HIZSDO BIT(3)
|
||||||
|
+#define SPICTL_STARTWR BIT(2)
|
||||||
|
+#define SPICTL_STARTRD BIT(1)
|
||||||
|
+#define SPICTL_SPIENA BIT(0)
|
||||||
|
+
|
||||||
|
+/* SPIUSER register bit field */
|
||||||
|
+#define SPIUSER_USERMODE BIT(21)
|
||||||
|
+#define SPIUSER_INSTR_PHASE BIT(20)
|
||||||
|
+#define SPIUSER_ADDR_PHASE_MASK 0x7
|
||||||
|
+#define SPIUSER_ADDR_PHASE_OFFSET 17
|
||||||
|
+#define SPIUSER_MODE_PHASE BIT(16)
|
||||||
|
+#define SPIUSER_DUMMY_PHASE_MASK 0x3
|
||||||
|
+#define SPIUSER_DUMMY_PHASE_OFFSET 14
|
||||||
|
+#define SPIUSER_DATA_PHASE_MASK 0x3
|
||||||
|
+#define SPIUSER_DATA_PHASE_OFFSET 12
|
||||||
|
+#define SPIUSER_DATA_READ (BIT(0) << SPIUSER_DATA_PHASE_OFFSET)
|
||||||
|
+#define SPIUSER_DATA_WRITE (BIT(1) << SPIUSER_DATA_PHASE_OFFSET)
|
||||||
|
+#define SPIUSER_ADDR_TYPE_OFFSET 9
|
||||||
|
+#define SPIUSER_MODE_TYPE_OFFSET 6
|
||||||
|
+#define SPIUSER_DUMMY_TYPE_OFFSET 3
|
||||||
|
+#define SPIUSER_DATA_TYPE_OFFSET 0
|
||||||
|
+#define SPIUSER_TRANSFER_MASK 0x7
|
||||||
|
+#define SPIUSER_TRANSFER_SINGLE BIT(0)
|
||||||
|
+#define SPIUSER_TRANSFER_DUAL BIT(1)
|
||||||
|
+#define SPIUSER_TRANSFER_QUAD BIT(2)
|
||||||
|
+
|
||||||
|
+#define SPIUSER_TRANSFER_TYPE(type) ( \
|
||||||
|
+ (type << SPIUSER_ADDR_TYPE_OFFSET) | \
|
||||||
|
+ (type << SPIUSER_MODE_TYPE_OFFSET) | \
|
||||||
|
+ (type << SPIUSER_DUMMY_TYPE_OFFSET) | \
|
||||||
|
+ (type << SPIUSER_DATA_TYPE_OFFSET) \
|
||||||
|
+)
|
||||||
|
+
|
||||||
|
+/* SPIFIFOSTAT register bit field */
|
||||||
|
+#define SPIFIFOSTAT_TXEMPTY BIT(19)
|
||||||
|
+#define SPIFIFOSTAT_RXEMPTY BIT(18)
|
||||||
|
+#define SPIFIFOSTAT_TXFULL BIT(17)
|
||||||
|
+#define SPIFIFOSTAT_RXFULL BIT(16)
|
||||||
|
+#define SPIFIFOSTAT_FIFO_MASK 0xff
|
||||||
|
+#define SPIFIFOSTAT_TX_OFFSET 8
|
||||||
|
+#define SPIFIFOSTAT_RX_OFFSET 0
|
||||||
|
+
|
||||||
|
+#define SPI_FIFO_DEPTH 16
|
||||||
|
+
|
||||||
|
+/* SPIMODE register bit field */
|
||||||
|
+#define SPIMODE_MODE_OFFSET 24
|
||||||
|
+#define SPIMODE_DUMMY_OFFSET 0
|
||||||
|
+
|
||||||
|
+/* SPIARB register bit field */
|
||||||
|
+#define SPICTL_ARB_EN BIT(31)
|
||||||
|
+#define SPICTL_CSCTL1 BIT(16)
|
||||||
|
+#define SPI1_POR BIT(1)
|
||||||
|
+#define SPI0_POR BIT(0)
|
||||||
|
+
|
||||||
|
+#define RT2880_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | \
|
||||||
|
+ SPI_CS_HIGH)
|
||||||
|
+
|
||||||
|
+static atomic_t hw_reset_count = ATOMIC_INIT(0);
|
||||||
|
+
|
||||||
|
+struct rt2880_spi {
|
||||||
|
+ struct spi_master *master;
|
||||||
|
+ void __iomem *base;
|
||||||
|
+ u32 speed;
|
||||||
|
+ u16 wait_loops;
|
||||||
|
+ u16 mode;
|
||||||
|
+ struct clk *clk;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static inline struct rt2880_spi *spidev_to_rt2880_spi(struct spi_device *spi)
|
||||||
|
+{
|
||||||
|
+ return spi_master_get_devdata(spi->master);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline u32 rt2880_spi_read(struct rt2880_spi *rs, u32 reg)
|
||||||
|
+{
|
||||||
|
+ return ioread32(rs->base + reg);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void rt2880_spi_write(struct rt2880_spi *rs, u32 reg,
|
||||||
|
+ const u32 val)
|
||||||
|
+{
|
||||||
|
+ iowrite32(val, rs->base + reg);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void rt2880_spi_setbits(struct rt2880_spi *rs, u32 reg, u32 mask)
|
||||||
|
+{
|
||||||
|
+ void __iomem *addr = rs->base + reg;
|
||||||
|
+
|
||||||
|
+ iowrite32((ioread32(addr) | mask), addr);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void rt2880_spi_clrbits(struct rt2880_spi *rs, u32 reg, u32 mask)
|
||||||
|
+{
|
||||||
|
+ void __iomem *addr = rs->base + reg;
|
||||||
|
+
|
||||||
|
+ iowrite32((ioread32(addr) & ~mask), addr);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static u32 rt2880_spi_baudrate_get(struct spi_device *spi, unsigned int speed)
|
||||||
|
+{
|
||||||
|
+ struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
|
||||||
|
+ u32 rate;
|
||||||
|
+ u32 prescale;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * the supported rates are: 2, 4, 8, ... 128
|
||||||
|
+ * round up as we look for equal or less speed
|
||||||
|
+ */
|
||||||
|
+ rate = DIV_ROUND_UP(clk_get_rate(rs->clk), speed);
|
||||||
|
+ rate = roundup_pow_of_two(rate);
|
||||||
|
+
|
||||||
|
+ /* Convert the rate to SPI clock divisor value. */
|
||||||
|
+ prescale = ilog2(rate / 2);
|
||||||
|
+
|
||||||
|
+ /* some tolerance. double and add 100 */
|
||||||
|
+ rs->wait_loops = (8 * HZ * loops_per_jiffy) /
|
||||||
|
+ (clk_get_rate(rs->clk) / rate);
|
||||||
|
+ rs->wait_loops = (rs->wait_loops << 1) + 100;
|
||||||
|
+ rs->speed = speed;
|
||||||
|
+
|
||||||
|
+ dev_dbg(&spi->dev, "speed: %lu/%u, rate: %u, prescal: %u, loops: %hu\n",
|
||||||
|
+ clk_get_rate(rs->clk) / rate, speed, rate, prescale,
|
||||||
|
+ rs->wait_loops);
|
||||||
|
+
|
||||||
|
+ return prescale;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static u32 get_arbiter_offset(struct spi_master *master)
|
||||||
|
+{
|
||||||
|
+ u32 offset;
|
||||||
|
+
|
||||||
|
+ offset = RAMIPS_SPI_ARBITER;
|
||||||
|
+ if (master->bus_num == 1)
|
||||||
|
+ offset -= RAMIPS_SPI_DEV_OFFSET;
|
||||||
|
+
|
||||||
|
+ return offset;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void rt2880_spi_set_cs(struct spi_device *spi, bool enable)
|
||||||
|
+{
|
||||||
|
+ struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
|
||||||
|
+
|
||||||
|
+ if (enable)
|
||||||
|
+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
|
||||||
|
+ else
|
||||||
|
+ rt2880_spi_clrbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int rt2880_spi_wait_ready(struct rt2880_spi *rs, int len)
|
||||||
|
+{
|
||||||
|
+ int loop = rs->wait_loops * len;
|
||||||
|
+
|
||||||
|
+ while ((rt2880_spi_read(rs, RAMIPS_SPI_STAT) & SPISTAT_BUSY) && --loop)
|
||||||
|
+ cpu_relax();
|
||||||
|
+
|
||||||
|
+ if (loop)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ return -ETIMEDOUT;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void rt2880_dump_reg(struct spi_master *master)
|
||||||
|
+{
|
||||||
|
+ struct rt2880_spi *rs = spi_master_get_devdata(master);
|
||||||
|
+
|
||||||
|
+ dev_dbg(&master->dev, "stat: %08x, cfg: %08x, ctl: %08x, " \
|
||||||
|
+ "data: %08x, arb: %08x\n",
|
||||||
|
+ rt2880_spi_read(rs, RAMIPS_SPI_STAT),
|
||||||
|
+ rt2880_spi_read(rs, RAMIPS_SPI_CFG),
|
||||||
|
+ rt2880_spi_read(rs, RAMIPS_SPI_CTL),
|
||||||
|
+ rt2880_spi_read(rs, RAMIPS_SPI_DATA),
|
||||||
|
+ rt2880_spi_read(rs, get_arbiter_offset(master)));
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int rt2880_spi_transfer_one(struct spi_master *master,
|
||||||
|
+ struct spi_device *spi, struct spi_transfer *xfer)
|
||||||
|
+{
|
||||||
|
+ struct rt2880_spi *rs = spi_master_get_devdata(master);
|
||||||
|
+ unsigned len;
|
||||||
|
+ const u8 *tx = xfer->tx_buf;
|
||||||
|
+ u8 *rx = xfer->rx_buf;
|
||||||
|
+ int err = 0;
|
||||||
|
+
|
||||||
|
+ /* change clock speed */
|
||||||
|
+ if (unlikely(rs->speed != xfer->speed_hz)) {
|
||||||
|
+ u32 reg;
|
||||||
|
+ reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG);
|
||||||
|
+ reg &= ~SPICFG_SPICLK_PRESCALE_MASK;
|
||||||
|
+ reg |= rt2880_spi_baudrate_get(spi, xfer->speed_hz);
|
||||||
|
+ rt2880_spi_write(rs, RAMIPS_SPI_CFG, reg);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (tx) {
|
||||||
|
+ len = xfer->len;
|
||||||
|
+ while (len-- > 0) {
|
||||||
|
+ rt2880_spi_write(rs, RAMIPS_SPI_DATA, *tx++);
|
||||||
|
+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTWR);
|
||||||
|
+ err = rt2880_spi_wait_ready(rs, 1);
|
||||||
|
+ if (err) {
|
||||||
|
+ dev_err(&spi->dev, "TX failed, err=%d\n", err);
|
||||||
|
+ goto out;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (rx) {
|
||||||
|
+ len = xfer->len;
|
||||||
|
+ while (len-- > 0) {
|
||||||
|
+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTRD);
|
||||||
|
+ err = rt2880_spi_wait_ready(rs, 1);
|
||||||
|
+ if (err) {
|
||||||
|
+ dev_err(&spi->dev, "RX failed, err=%d\n", err);
|
||||||
|
+ goto out;
|
||||||
|
+ }
|
||||||
|
+ *rx++ = (u8) rt2880_spi_read(rs, RAMIPS_SPI_DATA);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+out:
|
||||||
|
+ return err;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* copy from spi.c */
|
||||||
|
+static void spi_set_cs(struct spi_device *spi, bool enable)
|
||||||
|
+{
|
||||||
|
+ if (spi->mode & SPI_CS_HIGH)
|
||||||
|
+ enable = !enable;
|
||||||
|
+
|
||||||
|
+ if (spi->cs_gpio >= 0)
|
||||||
|
+ gpio_set_value(spi->cs_gpio, !enable);
|
||||||
|
+ else if (spi->master->set_cs)
|
||||||
|
+ spi->master->set_cs(spi, !enable);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int rt2880_spi_setup(struct spi_device *spi)
|
||||||
|
+{
|
||||||
|
+ struct spi_master *master = spi->master;
|
||||||
|
+ struct rt2880_spi *rs = spi_master_get_devdata(master);
|
||||||
|
+ u32 reg, old_reg, arbit_off;
|
||||||
|
+
|
||||||
|
+ if ((spi->max_speed_hz > master->max_speed_hz) ||
|
||||||
|
+ (spi->max_speed_hz < master->min_speed_hz)) {
|
||||||
|
+ dev_err(&spi->dev, "invalide requested speed %d Hz\n",
|
||||||
|
+ spi->max_speed_hz);
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!(master->bits_per_word_mask &
|
||||||
|
+ BIT(spi->bits_per_word - 1))) {
|
||||||
|
+ dev_err(&spi->dev, "invalide bits_per_word %d\n",
|
||||||
|
+ spi->bits_per_word);
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* the hardware seems can't work on mode0 force it to mode3 */
|
||||||
|
+ if ((spi->mode & (SPI_CPOL | SPI_CPHA)) == SPI_MODE_0) {
|
||||||
|
+ dev_warn(&spi->dev, "force spi mode3\n");
|
||||||
|
+ spi->mode |= SPI_MODE_3;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* chip polarity */
|
||||||
|
+ arbit_off = get_arbiter_offset(master);
|
||||||
|
+ reg = old_reg = rt2880_spi_read(rs, arbit_off);
|
||||||
|
+ if (spi->mode & SPI_CS_HIGH) {
|
||||||
|
+ switch (master->bus_num) {
|
||||||
|
+ case 1:
|
||||||
|
+ reg |= SPI1_POR;
|
||||||
|
+ break;
|
||||||
|
+ default:
|
||||||
|
+ reg |= SPI0_POR;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ switch (master->bus_num) {
|
||||||
|
+ case 1:
|
||||||
|
+ reg &= ~SPI1_POR;
|
||||||
|
+ break;
|
||||||
|
+ default:
|
||||||
|
+ reg &= ~SPI0_POR;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* enable spi1 */
|
||||||
|
+ if (master->bus_num == 1)
|
||||||
|
+ reg |= SPICTL_ARB_EN;
|
||||||
|
+
|
||||||
|
+ if (reg != old_reg)
|
||||||
|
+ rt2880_spi_write(rs, arbit_off, reg);
|
||||||
|
+
|
||||||
|
+ /* deselected the spi device */
|
||||||
|
+ spi_set_cs(spi, false);
|
||||||
|
+
|
||||||
|
+ rt2880_dump_reg(master);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int rt2880_spi_prepare_message(struct spi_master *master,
|
||||||
|
+ struct spi_message *msg)
|
||||||
|
+{
|
||||||
|
+ struct rt2880_spi *rs = spi_master_get_devdata(master);
|
||||||
|
+ struct spi_device *spi = msg->spi;
|
||||||
|
+ u32 reg;
|
||||||
|
+
|
||||||
|
+ if ((rs->mode == spi->mode) && (rs->speed == spi->max_speed_hz))
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+#if 0
|
||||||
|
+ /* set spido to tri-state */
|
||||||
|
+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_HIZSDO);
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+ reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG);
|
||||||
|
+
|
||||||
|
+ reg &= ~(SPICFG_MSBFIRST | SPICFG_SPICLKPOL |
|
||||||
|
+ SPICFG_RXCLKEDGE_FALLING |
|
||||||
|
+ SPICFG_TXCLKEDGE_FALLING |
|
||||||
|
+ SPICFG_SPICLK_PRESCALE_MASK);
|
||||||
|
+
|
||||||
|
+ /* MSB */
|
||||||
|
+ if (!(spi->mode & SPI_LSB_FIRST))
|
||||||
|
+ reg |= SPICFG_MSBFIRST;
|
||||||
|
+
|
||||||
|
+ /* spi mode */
|
||||||
|
+ switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
|
||||||
|
+ case SPI_MODE_0:
|
||||||
|
+ reg |= SPICFG_TXCLKEDGE_FALLING;
|
||||||
|
+ break;
|
||||||
|
+ case SPI_MODE_1:
|
||||||
|
+ reg |= SPICFG_RXCLKEDGE_FALLING;
|
||||||
|
+ break;
|
||||||
|
+ case SPI_MODE_2:
|
||||||
|
+ reg |= SPICFG_SPICLKPOL | SPICFG_RXCLKEDGE_FALLING;
|
||||||
|
+ break;
|
||||||
|
+ case SPI_MODE_3:
|
||||||
|
+ reg |= SPICFG_SPICLKPOL | SPICFG_TXCLKEDGE_FALLING;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ rs->mode = spi->mode;
|
||||||
|
+
|
||||||
|
+#if 0
|
||||||
|
+ /* set spiclk and spiena to tri-state */
|
||||||
|
+ reg |= SPICFG_HIZSPI;
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+ /* clock divide */
|
||||||
|
+ reg |= rt2880_spi_baudrate_get(spi, spi->max_speed_hz);
|
||||||
|
+
|
||||||
|
+ rt2880_spi_write(rs, RAMIPS_SPI_CFG, reg);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int rt2880_spi_probe(struct platform_device *pdev)
|
||||||
|
+{
|
||||||
|
+ struct spi_master *master;
|
||||||
|
+ struct rt2880_spi *rs;
|
||||||
|
+ void __iomem *base;
|
||||||
|
+ struct resource *r;
|
||||||
|
+ struct clk *clk;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
+ base = devm_ioremap_resource(&pdev->dev, r);
|
||||||
|
+ if (IS_ERR(base))
|
||||||
|
+ return PTR_ERR(base);
|
||||||
|
+
|
||||||
|
+ clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
|
+ if (IS_ERR(clk)) {
|
||||||
|
+ dev_err(&pdev->dev, "unable to get SYS clock\n");
|
||||||
|
+ return PTR_ERR(clk);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ret = clk_prepare_enable(clk);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto err_clk;
|
||||||
|
+
|
||||||
|
+ master = spi_alloc_master(&pdev->dev, sizeof(*rs));
|
||||||
|
+ if (master == NULL) {
|
||||||
|
+ dev_dbg(&pdev->dev, "master allocation failed\n");
|
||||||
|
+ ret = -ENOMEM;
|
||||||
|
+ goto err_clk;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ master->dev.of_node = pdev->dev.of_node;
|
||||||
|
+ master->mode_bits = RT2880_SPI_MODE_BITS;
|
||||||
|
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
|
||||||
|
+ master->min_speed_hz = clk_get_rate(clk) / 128;
|
||||||
|
+ master->max_speed_hz = clk_get_rate(clk) / 2;
|
||||||
|
+ master->flags = SPI_MASTER_HALF_DUPLEX;
|
||||||
|
+ master->setup = rt2880_spi_setup;
|
||||||
|
+ master->prepare_message = rt2880_spi_prepare_message;
|
||||||
|
+ master->set_cs = rt2880_spi_set_cs;
|
||||||
|
+ master->transfer_one = rt2880_spi_transfer_one,
|
||||||
|
+
|
||||||
|
+ dev_set_drvdata(&pdev->dev, master);
|
||||||
|
+
|
||||||
|
+ rs = spi_master_get_devdata(master);
|
||||||
|
+ rs->master = master;
|
||||||
|
+ rs->base = base;
|
||||||
|
+ rs->clk = clk;
|
||||||
|
+
|
||||||
|
+ if (atomic_inc_return(&hw_reset_count) == 1)
|
||||||
|
+ device_reset(&pdev->dev);
|
||||||
|
+
|
||||||
|
+ ret = devm_spi_register_master(&pdev->dev, master);
|
||||||
|
+ if (ret < 0) {
|
||||||
|
+ dev_err(&pdev->dev, "devm_spi_register_master error.\n");
|
||||||
|
+ goto err_master;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
+err_master:
|
||||||
|
+ spi_master_put(master);
|
||||||
|
+ kfree(master);
|
||||||
|
+err_clk:
|
||||||
|
+ clk_disable_unprepare(clk);
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int rt2880_spi_remove(struct platform_device *pdev)
|
||||||
|
+{
|
||||||
|
+ struct spi_master *master;
|
||||||
|
+ struct rt2880_spi *rs;
|
||||||
|
+
|
||||||
|
+ master = dev_get_drvdata(&pdev->dev);
|
||||||
|
+ rs = spi_master_get_devdata(master);
|
||||||
|
+
|
||||||
|
+ clk_disable_unprepare(rs->clk);
|
||||||
|
+ atomic_dec(&hw_reset_count);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+MODULE_ALIAS("platform:" DRIVER_NAME);
|
||||||
|
+
|
||||||
|
+static const struct of_device_id rt2880_spi_match[] = {
|
||||||
|
+ { .compatible = "ralink,rt2880-spi" },
|
||||||
|
+ {},
|
||||||
|
+};
|
||||||
|
+MODULE_DEVICE_TABLE(of, rt2880_spi_match);
|
||||||
|
+
|
||||||
|
+static struct platform_driver rt2880_spi_driver = {
|
||||||
|
+ .driver = {
|
||||||
|
+ .name = DRIVER_NAME,
|
||||||
|
+ .owner = THIS_MODULE,
|
||||||
|
+ .of_match_table = rt2880_spi_match,
|
||||||
|
+ },
|
||||||
|
+ .probe = rt2880_spi_probe,
|
||||||
|
+ .remove = rt2880_spi_remove,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+module_platform_driver(rt2880_spi_driver);
|
||||||
|
+
|
||||||
|
+MODULE_DESCRIPTION("Ralink SPI driver");
|
||||||
|
+MODULE_AUTHOR("Sergiy <piratfm@gmail.com>");
|
||||||
|
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
|
||||||
|
+MODULE_LICENSE("GPL");
|
@ -0,0 +1,507 @@
|
|||||||
|
From 723b8beaabf3c3c4b1ce69480141f1e926f3f3b2 Mon Sep 17 00:00:00 2001
|
||||||
|
From: John Crispin <blogic@openwrt.org>
|
||||||
|
Date: Sun, 27 Jul 2014 09:52:56 +0100
|
||||||
|
Subject: [PATCH 44/53] i2c: MIPS: adds ralink I2C driver
|
||||||
|
|
||||||
|
Signed-off-by: John Crispin <blogic@openwrt.org>
|
||||||
|
---
|
||||||
|
.../devicetree/bindings/i2c/i2c-ralink.txt | 27 ++
|
||||||
|
drivers/i2c/busses/Kconfig | 4 +
|
||||||
|
drivers/i2c/busses/Makefile | 1 +
|
||||||
|
drivers/i2c/busses/i2c-ralink.c | 327 ++++++++++++++++++++
|
||||||
|
4 files changed, 359 insertions(+)
|
||||||
|
create mode 100644 Documentation/devicetree/bindings/i2c/i2c-ralink.txt
|
||||||
|
create mode 100644 drivers/i2c/busses/i2c-ralink.c
|
||||||
|
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/Documentation/devicetree/bindings/i2c/i2c-ralink.txt
|
||||||
|
@@ -0,0 +1,27 @@
|
||||||
|
+I2C for Ralink platforms
|
||||||
|
+
|
||||||
|
+Required properties :
|
||||||
|
+- compatible : Must be "link,rt3052-i2c"
|
||||||
|
+- reg: physical base address of the controller and length of memory mapped
|
||||||
|
+ region.
|
||||||
|
+- #address-cells = <1>;
|
||||||
|
+- #size-cells = <0>;
|
||||||
|
+
|
||||||
|
+Optional properties:
|
||||||
|
+- Child nodes conforming to i2c bus binding
|
||||||
|
+
|
||||||
|
+Example :
|
||||||
|
+
|
||||||
|
+palmbus@10000000 {
|
||||||
|
+ i2c@900 {
|
||||||
|
+ compatible = "link,rt3052-i2c";
|
||||||
|
+ reg = <0x900 0x100>;
|
||||||
|
+ #address-cells = <1>;
|
||||||
|
+ #size-cells = <0>;
|
||||||
|
+
|
||||||
|
+ hwmon@4b {
|
||||||
|
+ compatible = "national,lm92";
|
||||||
|
+ reg = <0x4b>;
|
||||||
|
+ };
|
||||||
|
+ };
|
||||||
|
+};
|
||||||
|
--- a/drivers/i2c/busses/Kconfig
|
||||||
|
+++ b/drivers/i2c/busses/Kconfig
|
||||||
|
@@ -922,6 +922,11 @@ config I2C_RK3X
|
||||||
|
This driver can also be built as a module. If so, the module will
|
||||||
|
be called i2c-rk3x.
|
||||||
|
|
||||||
|
+config I2C_RALINK
|
||||||
|
+ tristate "Ralink I2C Controller"
|
||||||
|
+ depends on RALINK && !SOC_MT7621
|
||||||
|
+ select OF_I2C
|
||||||
|
+
|
||||||
|
config HAVE_S3C2410_I2C
|
||||||
|
bool
|
||||||
|
help
|
||||||
|
--- a/drivers/i2c/busses/Makefile
|
||||||
|
+++ b/drivers/i2c/busses/Makefile
|
||||||
|
@@ -91,6 +91,7 @@ obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
|
||||||
|
obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o
|
||||||
|
obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
|
||||||
|
obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o
|
||||||
|
+obj-$(CONFIG_I2C_RALINK) += i2c-ralink.o
|
||||||
|
obj-$(CONFIG_I2C_QCOM_GENI) += i2c-qcom-geni.o
|
||||||
|
obj-$(CONFIG_I2C_QUP) += i2c-qup.o
|
||||||
|
obj-$(CONFIG_I2C_RIIC) += i2c-riic.o
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/drivers/i2c/busses/i2c-ralink.c
|
||||||
|
@@ -0,0 +1,435 @@
|
||||||
|
+/*
|
||||||
|
+ * drivers/i2c/busses/i2c-ralink.c
|
||||||
|
+ *
|
||||||
|
+ * Copyright (C) 2013 Steven Liu <steven_liu@mediatek.com>
|
||||||
|
+ * Copyright (C) 2016 Michael Lee <igvtee@gmail.com>
|
||||||
|
+ *
|
||||||
|
+ * Improve driver for i2cdetect from i2c-tools to detect i2c devices on the bus.
|
||||||
|
+ * (C) 2014 Sittisak <sittisaks@hotmail.com>
|
||||||
|
+ *
|
||||||
|
+ * This software is licensed under the terms of the GNU General Public
|
||||||
|
+ * License version 2, as published by the Free Software Foundation, and
|
||||||
|
+ * may be copied, distributed, and modified under those terms.
|
||||||
|
+ *
|
||||||
|
+ * This program is distributed in the hope that it will be useful,
|
||||||
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
+ * GNU General Public License for more details.
|
||||||
|
+ *
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <linux/interrupt.h>
|
||||||
|
+#include <linux/kernel.h>
|
||||||
|
+#include <linux/module.h>
|
||||||
|
+#include <linux/reset.h>
|
||||||
|
+#include <linux/delay.h>
|
||||||
|
+#include <linux/slab.h>
|
||||||
|
+#include <linux/init.h>
|
||||||
|
+#include <linux/errno.h>
|
||||||
|
+#include <linux/platform_device.h>
|
||||||
|
+#include <linux/of_platform.h>
|
||||||
|
+#include <linux/i2c.h>
|
||||||
|
+#include <linux/io.h>
|
||||||
|
+#include <linux/err.h>
|
||||||
|
+#include <linux/clk.h>
|
||||||
|
+
|
||||||
|
+#define REG_CONFIG_REG 0x00
|
||||||
|
+#define REG_CLKDIV_REG 0x04
|
||||||
|
+#define REG_DEVADDR_REG 0x08
|
||||||
|
+#define REG_ADDR_REG 0x0C
|
||||||
|
+#define REG_DATAOUT_REG 0x10
|
||||||
|
+#define REG_DATAIN_REG 0x14
|
||||||
|
+#define REG_STATUS_REG 0x18
|
||||||
|
+#define REG_STARTXFR_REG 0x1C
|
||||||
|
+#define REG_BYTECNT_REG 0x20
|
||||||
|
+
|
||||||
|
+/* REG_CONFIG_REG */
|
||||||
|
+#define I2C_ADDRLEN_OFFSET 5
|
||||||
|
+#define I2C_DEVADLEN_OFFSET 2
|
||||||
|
+#define I2C_ADDRLEN_MASK 0x3
|
||||||
|
+#define I2C_ADDR_DIS BIT(1)
|
||||||
|
+#define I2C_DEVADDR_DIS BIT(0)
|
||||||
|
+#define I2C_ADDRLEN_8 (7 << I2C_ADDRLEN_OFFSET)
|
||||||
|
+#define I2C_DEVADLEN_7 (6 << I2C_DEVADLEN_OFFSET)
|
||||||
|
+#define I2C_CONF_DEFAULT (I2C_ADDRLEN_8 | I2C_DEVADLEN_7)
|
||||||
|
+
|
||||||
|
+/* REG_CLKDIV_REG */
|
||||||
|
+#define I2C_CLKDIV_MASK 0xffff
|
||||||
|
+
|
||||||
|
+/* REG_DEVADDR_REG */
|
||||||
|
+#define I2C_DEVADDR_MASK 0x7f
|
||||||
|
+
|
||||||
|
+/* REG_ADDR_REG */
|
||||||
|
+#define I2C_ADDR_MASK 0xff
|
||||||
|
+
|
||||||
|
+/* REG_STATUS_REG */
|
||||||
|
+#define I2C_STARTERR BIT(4)
|
||||||
|
+#define I2C_ACKERR BIT(3)
|
||||||
|
+#define I2C_DATARDY BIT(2)
|
||||||
|
+#define I2C_SDOEMPTY BIT(1)
|
||||||
|
+#define I2C_BUSY BIT(0)
|
||||||
|
+
|
||||||
|
+/* REG_STARTXFR_REG */
|
||||||
|
+#define NOSTOP_CMD BIT(2)
|
||||||
|
+#define NODATA_CMD BIT(1)
|
||||||
|
+#define READ_CMD BIT(0)
|
||||||
|
+
|
||||||
|
+/* REG_BYTECNT_REG */
|
||||||
|
+#define BYTECNT_MAX 64
|
||||||
|
+#define SET_BYTECNT(x) (x - 1)
|
||||||
|
+
|
||||||
|
+/* timeout waiting for I2C devices to respond (clock streching) */
|
||||||
|
+#define TIMEOUT_MS 1000
|
||||||
|
+#define DELAY_INTERVAL_US 100
|
||||||
|
+
|
||||||
|
+struct rt_i2c {
|
||||||
|
+ void __iomem *base;
|
||||||
|
+ struct clk *clk;
|
||||||
|
+ struct device *dev;
|
||||||
|
+ struct i2c_adapter adap;
|
||||||
|
+ u32 cur_clk;
|
||||||
|
+ u32 clk_div;
|
||||||
|
+ u32 flags;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static void rt_i2c_w32(struct rt_i2c *i2c, u32 val, unsigned reg)
|
||||||
|
+{
|
||||||
|
+ iowrite32(val, i2c->base + reg);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static u32 rt_i2c_r32(struct rt_i2c *i2c, unsigned reg)
|
||||||
|
+{
|
||||||
|
+ return ioread32(i2c->base + reg);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int poll_down_timeout(void __iomem *addr, u32 mask)
|
||||||
|
+{
|
||||||
|
+ unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS);
|
||||||
|
+
|
||||||
|
+ do {
|
||||||
|
+ if (!(readl_relaxed(addr) & mask))
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50);
|
||||||
|
+ } while (time_before(jiffies, timeout));
|
||||||
|
+
|
||||||
|
+ return (readl_relaxed(addr) & mask) ? -EAGAIN : 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int rt_i2c_wait_idle(struct rt_i2c *i2c)
|
||||||
|
+{
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ ret = poll_down_timeout(i2c->base + REG_STATUS_REG, I2C_BUSY);
|
||||||
|
+ if (ret < 0)
|
||||||
|
+ dev_dbg(i2c->dev, "idle err(%d)\n", ret);
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int poll_up_timeout(void __iomem *addr, u32 mask)
|
||||||
|
+{
|
||||||
|
+ unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS);
|
||||||
|
+ u32 status;
|
||||||
|
+
|
||||||
|
+ do {
|
||||||
|
+ status = readl_relaxed(addr);
|
||||||
|
+
|
||||||
|
+ /* check error status */
|
||||||
|
+ if (status & I2C_STARTERR)
|
||||||
|
+ return -EAGAIN;
|
||||||
|
+ else if (status & I2C_ACKERR)
|
||||||
|
+ return -ENXIO;
|
||||||
|
+ else if (status & mask)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50);
|
||||||
|
+ } while (time_before(jiffies, timeout));
|
||||||
|
+
|
||||||
|
+ return -ETIMEDOUT;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int rt_i2c_wait_rx_done(struct rt_i2c *i2c)
|
||||||
|
+{
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ ret = poll_up_timeout(i2c->base + REG_STATUS_REG, I2C_DATARDY);
|
||||||
|
+ if (ret < 0)
|
||||||
|
+ dev_dbg(i2c->dev, "rx err(%d)\n", ret);
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int rt_i2c_wait_tx_done(struct rt_i2c *i2c)
|
||||||
|
+{
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ ret = poll_up_timeout(i2c->base + REG_STATUS_REG, I2C_SDOEMPTY);
|
||||||
|
+ if (ret < 0)
|
||||||
|
+ dev_dbg(i2c->dev, "tx err(%d)\n", ret);
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void rt_i2c_reset(struct rt_i2c *i2c)
|
||||||
|
+{
|
||||||
|
+ device_reset(i2c->adap.dev.parent);
|
||||||
|
+ barrier();
|
||||||
|
+ rt_i2c_w32(i2c, i2c->clk_div, REG_CLKDIV_REG);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void rt_i2c_dump_reg(struct rt_i2c *i2c)
|
||||||
|
+{
|
||||||
|
+ dev_dbg(i2c->dev, "conf %08x, clkdiv %08x, devaddr %08x, " \
|
||||||
|
+ "addr %08x, dataout %08x, datain %08x, " \
|
||||||
|
+ "status %08x, startxfr %08x, bytecnt %08x\n",
|
||||||
|
+ rt_i2c_r32(i2c, REG_CONFIG_REG),
|
||||||
|
+ rt_i2c_r32(i2c, REG_CLKDIV_REG),
|
||||||
|
+ rt_i2c_r32(i2c, REG_DEVADDR_REG),
|
||||||
|
+ rt_i2c_r32(i2c, REG_ADDR_REG),
|
||||||
|
+ rt_i2c_r32(i2c, REG_DATAOUT_REG),
|
||||||
|
+ rt_i2c_r32(i2c, REG_DATAIN_REG),
|
||||||
|
+ rt_i2c_r32(i2c, REG_STATUS_REG),
|
||||||
|
+ rt_i2c_r32(i2c, REG_STARTXFR_REG),
|
||||||
|
+ rt_i2c_r32(i2c, REG_BYTECNT_REG));
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int rt_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||||
|
+ int num)
|
||||||
|
+{
|
||||||
|
+ struct rt_i2c *i2c;
|
||||||
|
+ struct i2c_msg *pmsg;
|
||||||
|
+ unsigned char addr;
|
||||||
|
+ int i, j, ret;
|
||||||
|
+ u32 cmd;
|
||||||
|
+
|
||||||
|
+ i2c = i2c_get_adapdata(adap);
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < num; i++) {
|
||||||
|
+ pmsg = &msgs[i];
|
||||||
|
+ if (i == (num - 1))
|
||||||
|
+ cmd = 0;
|
||||||
|
+ else
|
||||||
|
+ cmd = NOSTOP_CMD;
|
||||||
|
+
|
||||||
|
+ dev_dbg(i2c->dev, "addr: 0x%x, len: %d, flags: 0x%x, stop: %d\n",
|
||||||
|
+ pmsg->addr, pmsg->len, pmsg->flags,
|
||||||
|
+ (cmd == 0)? 1 : 0);
|
||||||
|
+
|
||||||
|
+ /* wait hardware idle */
|
||||||
|
+ if ((ret = rt_i2c_wait_idle(i2c)))
|
||||||
|
+ goto err_timeout;
|
||||||
|
+
|
||||||
|
+ if (pmsg->flags & I2C_M_TEN) {
|
||||||
|
+ rt_i2c_w32(i2c, I2C_CONF_DEFAULT, REG_CONFIG_REG);
|
||||||
|
+ /* 10 bits address */
|
||||||
|
+ addr = 0x78 | ((pmsg->addr >> 8) & 0x03);
|
||||||
|
+ rt_i2c_w32(i2c, addr & I2C_DEVADDR_MASK,
|
||||||
|
+ REG_DEVADDR_REG);
|
||||||
|
+ rt_i2c_w32(i2c, pmsg->addr & I2C_ADDR_MASK,
|
||||||
|
+ REG_ADDR_REG);
|
||||||
|
+ } else {
|
||||||
|
+ rt_i2c_w32(i2c, I2C_CONF_DEFAULT | I2C_ADDR_DIS,
|
||||||
|
+ REG_CONFIG_REG);
|
||||||
|
+ /* 7 bits address */
|
||||||
|
+ rt_i2c_w32(i2c, pmsg->addr & I2C_DEVADDR_MASK,
|
||||||
|
+ REG_DEVADDR_REG);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* buffer length */
|
||||||
|
+ if (pmsg->len == 0)
|
||||||
|
+ cmd |= NODATA_CMD;
|
||||||
|
+ else
|
||||||
|
+ rt_i2c_w32(i2c, SET_BYTECNT(pmsg->len),
|
||||||
|
+ REG_BYTECNT_REG);
|
||||||
|
+
|
||||||
|
+ j = 0;
|
||||||
|
+ if (pmsg->flags & I2C_M_RD) {
|
||||||
|
+ cmd |= READ_CMD;
|
||||||
|
+ /* start transfer */
|
||||||
|
+ barrier();
|
||||||
|
+ rt_i2c_w32(i2c, cmd, REG_STARTXFR_REG);
|
||||||
|
+ do {
|
||||||
|
+ /* wait */
|
||||||
|
+ if ((ret = rt_i2c_wait_rx_done(i2c)))
|
||||||
|
+ goto err_timeout;
|
||||||
|
+ /* read data */
|
||||||
|
+ if (pmsg->len)
|
||||||
|
+ pmsg->buf[j] = rt_i2c_r32(i2c,
|
||||||
|
+ REG_DATAIN_REG);
|
||||||
|
+ j++;
|
||||||
|
+ } while (j < pmsg->len);
|
||||||
|
+ } else {
|
||||||
|
+ do {
|
||||||
|
+ /* write data */
|
||||||
|
+ if (pmsg->len)
|
||||||
|
+ rt_i2c_w32(i2c, pmsg->buf[j],
|
||||||
|
+ REG_DATAOUT_REG);
|
||||||
|
+ /* start transfer */
|
||||||
|
+ if (j == 0) {
|
||||||
|
+ barrier();
|
||||||
|
+ rt_i2c_w32(i2c, cmd, REG_STARTXFR_REG);
|
||||||
|
+ }
|
||||||
|
+ /* wait */
|
||||||
|
+ if ((ret = rt_i2c_wait_tx_done(i2c)))
|
||||||
|
+ goto err_timeout;
|
||||||
|
+ j++;
|
||||||
|
+ } while (j < pmsg->len);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ /* the return value is number of executed messages */
|
||||||
|
+ ret = i;
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
+err_timeout:
|
||||||
|
+ rt_i2c_dump_reg(i2c);
|
||||||
|
+ rt_i2c_reset(i2c);
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static u32 rt_i2c_func(struct i2c_adapter *a)
|
||||||
|
+{
|
||||||
|
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static const struct i2c_algorithm rt_i2c_algo = {
|
||||||
|
+ .master_xfer = rt_i2c_master_xfer,
|
||||||
|
+ .functionality = rt_i2c_func,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static const struct of_device_id i2c_rt_dt_ids[] = {
|
||||||
|
+ { .compatible = "ralink,rt2880-i2c" },
|
||||||
|
+ { /* sentinel */ }
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+MODULE_DEVICE_TABLE(of, i2c_rt_dt_ids);
|
||||||
|
+
|
||||||
|
+static struct i2c_adapter_quirks rt_i2c_quirks = {
|
||||||
|
+ .max_write_len = BYTECNT_MAX,
|
||||||
|
+ .max_read_len = BYTECNT_MAX,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static int rt_i2c_init(struct rt_i2c *i2c)
|
||||||
|
+{
|
||||||
|
+ u32 reg;
|
||||||
|
+
|
||||||
|
+ /* i2c_sclk = periph_clk / ((2 * clk_div) + 5) */
|
||||||
|
+ i2c->clk_div = (clk_get_rate(i2c->clk) - (5 * i2c->cur_clk)) /
|
||||||
|
+ (2 * i2c->cur_clk);
|
||||||
|
+ if (i2c->clk_div < 8)
|
||||||
|
+ i2c->clk_div = 8;
|
||||||
|
+ if (i2c->clk_div > I2C_CLKDIV_MASK)
|
||||||
|
+ i2c->clk_div = I2C_CLKDIV_MASK;
|
||||||
|
+
|
||||||
|
+ /* check support combinde/repeated start message */
|
||||||
|
+ rt_i2c_w32(i2c, NOSTOP_CMD, REG_STARTXFR_REG);
|
||||||
|
+ reg = rt_i2c_r32(i2c, REG_STARTXFR_REG) & NOSTOP_CMD;
|
||||||
|
+
|
||||||
|
+ rt_i2c_reset(i2c);
|
||||||
|
+
|
||||||
|
+ return reg;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int rt_i2c_probe(struct platform_device *pdev)
|
||||||
|
+{
|
||||||
|
+ struct resource *res;
|
||||||
|
+ struct rt_i2c *i2c;
|
||||||
|
+ struct i2c_adapter *adap;
|
||||||
|
+ const struct of_device_id *match;
|
||||||
|
+ int ret, restart;
|
||||||
|
+
|
||||||
|
+ match = of_match_device(i2c_rt_dt_ids, &pdev->dev);
|
||||||
|
+
|
||||||
|
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
+ if (!res) {
|
||||||
|
+ dev_err(&pdev->dev, "no memory resource found\n");
|
||||||
|
+ return -ENODEV;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ i2c = devm_kzalloc(&pdev->dev, sizeof(struct rt_i2c), GFP_KERNEL);
|
||||||
|
+ if (!i2c) {
|
||||||
|
+ dev_err(&pdev->dev, "failed to allocate i2c_adapter\n");
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ i2c->base = devm_ioremap_resource(&pdev->dev, res);
|
||||||
|
+ if (IS_ERR(i2c->base))
|
||||||
|
+ return PTR_ERR(i2c->base);
|
||||||
|
+
|
||||||
|
+ i2c->clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
|
+ if (IS_ERR(i2c->clk)) {
|
||||||
|
+ dev_err(&pdev->dev, "no clock defined\n");
|
||||||
|
+ return -ENODEV;
|
||||||
|
+ }
|
||||||
|
+ clk_prepare_enable(i2c->clk);
|
||||||
|
+ i2c->dev = &pdev->dev;
|
||||||
|
+
|
||||||
|
+ if (of_property_read_u32(pdev->dev.of_node,
|
||||||
|
+ "clock-frequency", &i2c->cur_clk))
|
||||||
|
+ i2c->cur_clk = 100000;
|
||||||
|
+
|
||||||
|
+ adap = &i2c->adap;
|
||||||
|
+ adap->owner = THIS_MODULE;
|
||||||
|
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
|
||||||
|
+ adap->algo = &rt_i2c_algo;
|
||||||
|
+ adap->retries = 3;
|
||||||
|
+ adap->dev.parent = &pdev->dev;
|
||||||
|
+ i2c_set_adapdata(adap, i2c);
|
||||||
|
+ adap->dev.of_node = pdev->dev.of_node;
|
||||||
|
+ strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name));
|
||||||
|
+ adap->quirks = &rt_i2c_quirks;
|
||||||
|
+
|
||||||
|
+ platform_set_drvdata(pdev, i2c);
|
||||||
|
+
|
||||||
|
+ restart = rt_i2c_init(i2c);
|
||||||
|
+
|
||||||
|
+ ret = i2c_add_adapter(adap);
|
||||||
|
+ if (ret < 0) {
|
||||||
|
+ dev_err(&pdev->dev, "failed to add adapter\n");
|
||||||
|
+ clk_disable_unprepare(i2c->clk);
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ dev_info(&pdev->dev, "clock %uKHz, re-start %ssupport\n",
|
||||||
|
+ i2c->cur_clk/1000, restart ? "" : "not ");
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int rt_i2c_remove(struct platform_device *pdev)
|
||||||
|
+{
|
||||||
|
+ struct rt_i2c *i2c = platform_get_drvdata(pdev);
|
||||||
|
+
|
||||||
|
+ i2c_del_adapter(&i2c->adap);
|
||||||
|
+ clk_disable_unprepare(i2c->clk);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static struct platform_driver rt_i2c_driver = {
|
||||||
|
+ .probe = rt_i2c_probe,
|
||||||
|
+ .remove = rt_i2c_remove,
|
||||||
|
+ .driver = {
|
||||||
|
+ .owner = THIS_MODULE,
|
||||||
|
+ .name = "i2c-ralink",
|
||||||
|
+ .of_match_table = i2c_rt_dt_ids,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static int __init i2c_rt_init (void)
|
||||||
|
+{
|
||||||
|
+ return platform_driver_register(&rt_i2c_driver);
|
||||||
|
+}
|
||||||
|
+subsys_initcall(i2c_rt_init);
|
||||||
|
+
|
||||||
|
+static void __exit i2c_rt_exit (void)
|
||||||
|
+{
|
||||||
|
+ platform_driver_unregister(&rt_i2c_driver);
|
||||||
|
+}
|
||||||
|
+module_exit(i2c_rt_exit);
|
||||||
|
+
|
||||||
|
+MODULE_AUTHOR("Steven Liu <steven_liu@mediatek.com>");
|
||||||
|
+MODULE_DESCRIPTION("Ralink I2c host driver");
|
||||||
|
+MODULE_LICENSE("GPL");
|
||||||
|
+MODULE_ALIAS("platform:Ralink-I2C");
|
@ -0,0 +1,43 @@
|
|||||||
|
From 23147af14531cbdada194b94120ef8774f46292d Mon Sep 17 00:00:00 2001
|
||||||
|
From: John Crispin <blogic@openwrt.org>
|
||||||
|
Date: Thu, 13 Nov 2014 19:08:40 +0100
|
||||||
|
Subject: [PATCH 46/53] mmc: MIPS: ralink: add sdhci for mt7620a SoC
|
||||||
|
|
||||||
|
Signed-off-by: John Crispin <blogic@openwrt.org>
|
||||||
|
---
|
||||||
|
drivers/mmc/host/Kconfig | 2 +
|
||||||
|
drivers/mmc/host/Makefile | 1 +
|
||||||
|
drivers/mmc/host/mtk-mmc/Kconfig | 16 +
|
||||||
|
drivers/mmc/host/mtk-mmc/Makefile | 42 +
|
||||||
|
drivers/mmc/host/mtk-mmc/board.h | 137 ++
|
||||||
|
drivers/mmc/host/mtk-mmc/dbg.c | 347 ++++
|
||||||
|
drivers/mmc/host/mtk-mmc/dbg.h | 156 ++
|
||||||
|
drivers/mmc/host/mtk-mmc/mt6575_sd.h | 1001 +++++++++++
|
||||||
|
drivers/mmc/host/mtk-mmc/sd.c | 3060 ++++++++++++++++++++++++++++++++++
|
||||||
|
9 files changed, 4762 insertions(+)
|
||||||
|
create mode 100644 drivers/mmc/host/mtk-mmc/Kconfig
|
||||||
|
create mode 100644 drivers/mmc/host/mtk-mmc/Makefile
|
||||||
|
create mode 100644 drivers/mmc/host/mtk-mmc/board.h
|
||||||
|
create mode 100644 drivers/mmc/host/mtk-mmc/dbg.c
|
||||||
|
create mode 100644 drivers/mmc/host/mtk-mmc/dbg.h
|
||||||
|
create mode 100644 drivers/mmc/host/mtk-mmc/mt6575_sd.h
|
||||||
|
create mode 100644 drivers/mmc/host/mtk-mmc/sd.c
|
||||||
|
|
||||||
|
--- a/drivers/mmc/host/Kconfig
|
||||||
|
+++ b/drivers/mmc/host/Kconfig
|
||||||
|
@@ -1019,3 +1019,5 @@ config MMC_SDHCI_AM654
|
||||||
|
If you have a controller with this interface, say Y or M here.
|
||||||
|
|
||||||
|
If unsure, say N.
|
||||||
|
+
|
||||||
|
+source "drivers/mmc/host/mtk-mmc/Kconfig"
|
||||||
|
--- a/drivers/mmc/host/Makefile
|
||||||
|
+++ b/drivers/mmc/host/Makefile
|
||||||
|
@@ -3,6 +3,7 @@
|
||||||
|
# Makefile for MMC/SD host controller drivers
|
||||||
|
#
|
||||||
|
|
||||||
|
+obj-$(CONFIG_MTK_MMC) += mtk-mmc/
|
||||||
|
obj-$(CONFIG_MMC_ARMMMCI) += armmmci.o
|
||||||
|
armmmci-y := mmci.o
|
||||||
|
armmmci-$(CONFIG_MMC_QCOM_DML) += mmci_qcom_dml.o
|
1046
target/linux/ramips/patches-5.10/0048-asoc-add-mt7620-support.patch
Normal file
1046
target/linux/ramips/patches-5.10/0048-asoc-add-mt7620-support.patch
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,22 @@
|
|||||||
|
From a7eb46e0ea4a11e4dfb56ab129bf816d1059a6c5 Mon Sep 17 00:00:00 2001
|
||||||
|
From: John Crispin <blogic@openwrt.org>
|
||||||
|
Date: Mon, 7 Dec 2015 17:31:08 +0100
|
||||||
|
Subject: [PATCH 51/53] serial: add ugly custom baud rate hack
|
||||||
|
|
||||||
|
Signed-off-by: John Crispin <blogic@openwrt.org>
|
||||||
|
---
|
||||||
|
drivers/tty/serial/serial_core.c | 3 +++
|
||||||
|
1 file changed, 3 insertions(+)
|
||||||
|
|
||||||
|
--- a/drivers/tty/serial/serial_core.c
|
||||||
|
+++ b/drivers/tty/serial/serial_core.c
|
||||||
|
@@ -416,6 +416,9 @@ uart_get_baud_rate(struct uart_port *por
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if (tty_termios_baud_rate(termios) == 2500000)
|
||||||
|
+ return 250000;
|
||||||
|
+
|
||||||
|
for (try = 0; try < 2; try++) {
|
||||||
|
baud = tty_termios_baud_rate(termios);
|
||||||
|
|
@ -0,0 +1,217 @@
|
|||||||
|
From fc8f96309c21c1bc3276427309cd7d361347d66e Mon Sep 17 00:00:00 2001
|
||||||
|
From: John Crispin <blogic@openwrt.org>
|
||||||
|
Date: Mon, 7 Dec 2015 17:16:50 +0100
|
||||||
|
Subject: [PATCH 52/53] pwm: add mediatek support
|
||||||
|
|
||||||
|
Signed-off-by: John Crispin <blogic@openwrt.org>
|
||||||
|
---
|
||||||
|
drivers/pwm/Kconfig | 9 +++
|
||||||
|
drivers/pwm/Makefile | 1 +
|
||||||
|
drivers/pwm/pwm-mediatek.c | 173 ++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
3 files changed, 183 insertions(+)
|
||||||
|
create mode 100644 drivers/pwm/pwm-mediatek.c
|
||||||
|
|
||||||
|
--- a/drivers/pwm/Kconfig
|
||||||
|
+++ b/drivers/pwm/Kconfig
|
||||||
|
@@ -316,6 +316,15 @@ config PWM_MEDIATEK
|
||||||
|
To compile this driver as a module, choose M here: the module
|
||||||
|
will be called pwm-mediatek.
|
||||||
|
|
||||||
|
+config PWM_MEDIATEK_RAMIPS
|
||||||
|
+ tristate "Mediatek PWM support"
|
||||||
|
+ depends on RALINK && OF
|
||||||
|
+ help
|
||||||
|
+ Generic PWM framework driver for Mediatek ARM SoC.
|
||||||
|
+
|
||||||
|
+ To compile this driver as a module, choose M here: the module
|
||||||
|
+ will be called pwm-mxs.
|
||||||
|
+
|
||||||
|
config PWM_MXS
|
||||||
|
tristate "Freescale MXS PWM support"
|
||||||
|
depends on ARCH_MXS && OF
|
||||||
|
--- a/drivers/pwm/Makefile
|
||||||
|
+++ b/drivers/pwm/Makefile
|
||||||
|
@@ -29,6 +29,7 @@ obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-p
|
||||||
|
obj-$(CONFIG_PWM_LPSS_PLATFORM) += pwm-lpss-platform.o
|
||||||
|
obj-$(CONFIG_PWM_MESON) += pwm-meson.o
|
||||||
|
obj-$(CONFIG_PWM_MEDIATEK) += pwm-mediatek.o
|
||||||
|
+obj-$(CONFIG_PWM_MEDIATEK_RAMIPS) += pwm-mediatek-ramips.o
|
||||||
|
obj-$(CONFIG_PWM_MTK_DISP) += pwm-mtk-disp.o
|
||||||
|
obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
|
||||||
|
obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-omap-dmtimer.o
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/drivers/pwm/pwm-mediatek-ramips.c
|
||||||
|
@@ -0,0 +1,173 @@
|
||||||
|
+/*
|
||||||
|
+ * Mediatek Pulse Width Modulator driver
|
||||||
|
+ *
|
||||||
|
+ * Copyright (C) 2015 John Crispin <blogic@openwrt.org>
|
||||||
|
+ *
|
||||||
|
+ * This file is licensed under the terms of the GNU General Public
|
||||||
|
+ * License version 2. This program is licensed "as is" without any
|
||||||
|
+ * warranty of any kind, whether express or implied.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <linux/err.h>
|
||||||
|
+#include <linux/io.h>
|
||||||
|
+#include <linux/ioport.h>
|
||||||
|
+#include <linux/kernel.h>
|
||||||
|
+#include <linux/module.h>
|
||||||
|
+#include <linux/of.h>
|
||||||
|
+#include <linux/platform_device.h>
|
||||||
|
+#include <linux/pwm.h>
|
||||||
|
+#include <linux/slab.h>
|
||||||
|
+#include <linux/types.h>
|
||||||
|
+
|
||||||
|
+#define NUM_PWM 4
|
||||||
|
+
|
||||||
|
+/* PWM registers and bits definitions */
|
||||||
|
+#define PWMCON 0x00
|
||||||
|
+#define PWMHDUR 0x04
|
||||||
|
+#define PWMLDUR 0x08
|
||||||
|
+#define PWMGDUR 0x0c
|
||||||
|
+#define PWMWAVENUM 0x28
|
||||||
|
+#define PWMDWIDTH 0x2c
|
||||||
|
+#define PWMTHRES 0x30
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * struct mtk_pwm_chip - struct representing pwm chip
|
||||||
|
+ *
|
||||||
|
+ * @mmio_base: base address of pwm chip
|
||||||
|
+ * @chip: linux pwm chip representation
|
||||||
|
+ */
|
||||||
|
+struct mtk_pwm_chip {
|
||||||
|
+ void __iomem *mmio_base;
|
||||||
|
+ struct pwm_chip chip;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static inline struct mtk_pwm_chip *to_mtk_pwm_chip(struct pwm_chip *chip)
|
||||||
|
+{
|
||||||
|
+ return container_of(chip, struct mtk_pwm_chip, chip);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline u32 mtk_pwm_readl(struct mtk_pwm_chip *chip, unsigned int num,
|
||||||
|
+ unsigned long offset)
|
||||||
|
+{
|
||||||
|
+ return ioread32(chip->mmio_base + 0x10 + (num * 0x40) + offset);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void mtk_pwm_writel(struct mtk_pwm_chip *chip,
|
||||||
|
+ unsigned int num, unsigned long offset,
|
||||||
|
+ unsigned long val)
|
||||||
|
+{
|
||||||
|
+ iowrite32(val, chip->mmio_base + 0x10 + (num * 0x40) + offset);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||||
|
+ int duty_ns, int period_ns)
|
||||||
|
+{
|
||||||
|
+ struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
|
||||||
|
+ u32 resolution = 100 / 4;
|
||||||
|
+ u32 clkdiv = 0;
|
||||||
|
+
|
||||||
|
+ while (period_ns / resolution > 8191) {
|
||||||
|
+ clkdiv++;
|
||||||
|
+ resolution *= 2;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (clkdiv > 7)
|
||||||
|
+ return -1;
|
||||||
|
+
|
||||||
|
+ mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | BIT(3) | clkdiv);
|
||||||
|
+ mtk_pwm_writel(pc, pwm->hwpwm, PWMDWIDTH, period_ns / resolution);
|
||||||
|
+ mtk_pwm_writel(pc, pwm->hwpwm, PWMTHRES, duty_ns / resolution);
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int mtk_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||||
|
+{
|
||||||
|
+ struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
|
||||||
|
+ u32 val;
|
||||||
|
+
|
||||||
|
+ val = ioread32(pc->mmio_base);
|
||||||
|
+ val |= BIT(pwm->hwpwm);
|
||||||
|
+ iowrite32(val, pc->mmio_base);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void mtk_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||||
|
+{
|
||||||
|
+ struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
|
||||||
|
+ u32 val;
|
||||||
|
+
|
||||||
|
+ val = ioread32(pc->mmio_base);
|
||||||
|
+ val &= ~BIT(pwm->hwpwm);
|
||||||
|
+ iowrite32(val, pc->mmio_base);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static const struct pwm_ops mtk_pwm_ops = {
|
||||||
|
+ .config = mtk_pwm_config,
|
||||||
|
+ .enable = mtk_pwm_enable,
|
||||||
|
+ .disable = mtk_pwm_disable,
|
||||||
|
+ .owner = THIS_MODULE,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static int mtk_pwm_probe(struct platform_device *pdev)
|
||||||
|
+{
|
||||||
|
+ struct mtk_pwm_chip *pc;
|
||||||
|
+ struct resource *r;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
|
||||||
|
+ if (!pc)
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+
|
||||||
|
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
+ pc->mmio_base = devm_ioremap_resource(&pdev->dev, r);
|
||||||
|
+ if (IS_ERR(pc->mmio_base))
|
||||||
|
+ return PTR_ERR(pc->mmio_base);
|
||||||
|
+
|
||||||
|
+ platform_set_drvdata(pdev, pc);
|
||||||
|
+
|
||||||
|
+ pc->chip.dev = &pdev->dev;
|
||||||
|
+ pc->chip.ops = &mtk_pwm_ops;
|
||||||
|
+ pc->chip.base = -1;
|
||||||
|
+ pc->chip.npwm = NUM_PWM;
|
||||||
|
+
|
||||||
|
+ ret = pwmchip_add(&pc->chip);
|
||||||
|
+ if (ret < 0)
|
||||||
|
+ dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int mtk_pwm_remove(struct platform_device *pdev)
|
||||||
|
+{
|
||||||
|
+ struct mtk_pwm_chip *pc = platform_get_drvdata(pdev);
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < NUM_PWM; i++)
|
||||||
|
+ pwm_disable(&pc->chip.pwms[i]);
|
||||||
|
+
|
||||||
|
+ return pwmchip_remove(&pc->chip);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static const struct of_device_id mtk_pwm_of_match[] = {
|
||||||
|
+ { .compatible = "mediatek,mt7628-pwm" },
|
||||||
|
+ { }
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+MODULE_DEVICE_TABLE(of, mtk_pwm_of_match);
|
||||||
|
+
|
||||||
|
+static struct platform_driver mtk_pwm_driver = {
|
||||||
|
+ .driver = {
|
||||||
|
+ .name = "mtk-pwm",
|
||||||
|
+ .owner = THIS_MODULE,
|
||||||
|
+ .of_match_table = mtk_pwm_of_match,
|
||||||
|
+ },
|
||||||
|
+ .probe = mtk_pwm_probe,
|
||||||
|
+ .remove = mtk_pwm_remove,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+module_platform_driver(mtk_pwm_driver);
|
||||||
|
+
|
||||||
|
+MODULE_LICENSE("GPL");
|
||||||
|
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
|
||||||
|
+MODULE_ALIAS("platform:mtk-pwm");
|
@ -0,0 +1,15 @@
|
|||||||
|
--- a/drivers/usb/dwc2/platform.c
|
||||||
|
+++ b/drivers/usb/dwc2/platform.c
|
||||||
|
@@ -431,6 +431,12 @@ static int dwc2_driver_probe(struct plat
|
||||||
|
if (retval)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
+ /* Enable USB port before any regs access */
|
||||||
|
+ if (readl(hsotg->regs + PCGCTL) & 0x0f) {
|
||||||
|
+ writel(0x00, hsotg->regs + PCGCTL);
|
||||||
|
+ /* TODO: mdelay(25) here? vendor driver don't use it */
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
hsotg->needs_byte_swap = dwc2_check_core_endianness(hsotg);
|
||||||
|
|
||||||
|
retval = dwc2_get_dr_mode(hsotg);
|
10
target/linux/ramips/patches-5.10/0070-weak_reordering.patch
Normal file
10
target/linux/ramips/patches-5.10/0070-weak_reordering.patch
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
--- a/arch/mips/ralink/Kconfig
|
||||||
|
+++ b/arch/mips/ralink/Kconfig
|
||||||
|
@@ -57,6 +57,7 @@ choice
|
||||||
|
select COMMON_CLK
|
||||||
|
select CLKSRC_MIPS_GIC
|
||||||
|
select HAVE_PCI if PCI_MT7621
|
||||||
|
+ select WEAK_REORDERING_BEYOND_LLSC
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
choice
|
19
target/linux/ramips/patches-5.10/0098-disable_cm.patch
Normal file
19
target/linux/ramips/patches-5.10/0098-disable_cm.patch
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
--- a/arch/mips/kernel/mips-cm.c
|
||||||
|
+++ b/arch/mips/kernel/mips-cm.c
|
||||||
|
@@ -233,6 +233,7 @@ int mips_cm_probe(void)
|
||||||
|
|
||||||
|
/* disable CM regions */
|
||||||
|
write_gcr_reg0_base(CM_GCR_REGn_BASE_BASEADDR);
|
||||||
|
+ /*
|
||||||
|
write_gcr_reg0_mask(CM_GCR_REGn_MASK_ADDRMASK);
|
||||||
|
write_gcr_reg1_base(CM_GCR_REGn_BASE_BASEADDR);
|
||||||
|
write_gcr_reg1_mask(CM_GCR_REGn_MASK_ADDRMASK);
|
||||||
|
@@ -240,7 +241,7 @@ int mips_cm_probe(void)
|
||||||
|
write_gcr_reg2_mask(CM_GCR_REGn_MASK_ADDRMASK);
|
||||||
|
write_gcr_reg3_base(CM_GCR_REGn_BASE_BASEADDR);
|
||||||
|
write_gcr_reg3_mask(CM_GCR_REGn_MASK_ADDRMASK);
|
||||||
|
-
|
||||||
|
+*/
|
||||||
|
/* probe for an L2-only sync region */
|
||||||
|
mips_cm_probe_l2sync();
|
||||||
|
|
@ -0,0 +1,133 @@
|
|||||||
|
From b327cd58c3fec1c6382128e929eab9bc0d68e912 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Sun, 8 Mar 2020 10:19:27 +0100
|
||||||
|
Subject: [PATCH] staging: mt7621-pci: simplify
|
||||||
|
'mt7621_pcie_init_virtual_bridges' function
|
||||||
|
|
||||||
|
Function 'mt7621_pcie_init_virtual_bridges' is a bit mess and can be
|
||||||
|
refactorized properly in a cleaner way. Introduce new 'pcie_rmw' inline
|
||||||
|
function helper to do clear and set the correct bits this function needs
|
||||||
|
to work.
|
||||||
|
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20200308091928.17177-1-sergio.paracuellos@gmail.com
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
---
|
||||||
|
drivers/staging/mt7621-pci/pci-mt7621.c | 85 +++++++++++++--------------------
|
||||||
|
1 file changed, 33 insertions(+), 52 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
@@ -57,13 +57,13 @@
|
||||||
|
#define RALINK_PCI_IOBASE 0x002C
|
||||||
|
|
||||||
|
/* PCICFG virtual bridges */
|
||||||
|
-#define MT7621_BR0_MASK GENMASK(19, 16)
|
||||||
|
-#define MT7621_BR1_MASK GENMASK(23, 20)
|
||||||
|
-#define MT7621_BR2_MASK GENMASK(27, 24)
|
||||||
|
-#define MT7621_BR_ALL_MASK GENMASK(27, 16)
|
||||||
|
-#define MT7621_BR0_SHIFT 16
|
||||||
|
-#define MT7621_BR1_SHIFT 20
|
||||||
|
-#define MT7621_BR2_SHIFT 24
|
||||||
|
+#define PCIE_P2P_MAX 3
|
||||||
|
+#define PCIE_P2P_BR_DEVNUM_SHIFT(p) (16 + (p) * 4)
|
||||||
|
+#define PCIE_P2P_BR_DEVNUM0_SHIFT PCIE_P2P_BR_DEVNUM_SHIFT(0)
|
||||||
|
+#define PCIE_P2P_BR_DEVNUM1_SHIFT PCIE_P2P_BR_DEVNUM_SHIFT(1)
|
||||||
|
+#define PCIE_P2P_BR_DEVNUM2_SHIFT PCIE_P2P_BR_DEVNUM_SHIFT(2)
|
||||||
|
+#define PCIE_P2P_BR_DEVNUM_MASK 0xf
|
||||||
|
+#define PCIE_P2P_BR_DEVNUM_MASK_FULL (0xfff << PCIE_P2P_BR_DEVNUM0_SHIFT)
|
||||||
|
|
||||||
|
/* PCIe RC control registers */
|
||||||
|
#define MT7621_PCIE_OFFSET 0x2000
|
||||||
|
@@ -154,6 +154,15 @@ static inline void pcie_write(struct mt7
|
||||||
|
writel(val, pcie->base + reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static inline void pcie_rmw(struct mt7621_pcie *pcie, u32 reg, u32 clr, u32 set)
|
||||||
|
+{
|
||||||
|
+ u32 val = readl(pcie->base + reg);
|
||||||
|
+
|
||||||
|
+ val &= ~clr;
|
||||||
|
+ val |= set;
|
||||||
|
+ writel(val, pcie->base + reg);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static inline u32 pcie_port_read(struct mt7621_pcie_port *port, u32 reg)
|
||||||
|
{
|
||||||
|
return readl(port->base + reg);
|
||||||
|
@@ -554,7 +563,9 @@ static void mt7621_pcie_enable_ports(str
|
||||||
|
static int mt7621_pcie_init_virtual_bridges(struct mt7621_pcie *pcie)
|
||||||
|
{
|
||||||
|
u32 pcie_link_status = 0;
|
||||||
|
- u32 val = 0;
|
||||||
|
+ u32 n;
|
||||||
|
+ int i;
|
||||||
|
+ u32 p2p_br_devnum[PCIE_P2P_MAX];
|
||||||
|
struct mt7621_pcie_port *port;
|
||||||
|
|
||||||
|
list_for_each_entry(port, &pcie->ports, list) {
|
||||||
|
@@ -567,50 +578,20 @@ static int mt7621_pcie_init_virtual_brid
|
||||||
|
if (pcie_link_status == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
- /*
|
||||||
|
- * pcie(2/1/0) link status pcie2_num pcie1_num pcie0_num
|
||||||
|
- * 3'b000 x x x
|
||||||
|
- * 3'b001 x x 0
|
||||||
|
- * 3'b010 x 0 x
|
||||||
|
- * 3'b011 x 1 0
|
||||||
|
- * 3'b100 0 x x
|
||||||
|
- * 3'b101 1 x 0
|
||||||
|
- * 3'b110 1 0 x
|
||||||
|
- * 3'b111 2 1 0
|
||||||
|
- */
|
||||||
|
- switch (pcie_link_status) {
|
||||||
|
- case 2:
|
||||||
|
- val = pcie_read(pcie, RALINK_PCI_PCICFG_ADDR);
|
||||||
|
- val &= ~(MT7621_BR0_MASK | MT7621_BR1_MASK);
|
||||||
|
- val |= 0x1 << MT7621_BR0_SHIFT;
|
||||||
|
- val |= 0x0 << MT7621_BR1_SHIFT;
|
||||||
|
- pcie_write(pcie, val, RALINK_PCI_PCICFG_ADDR);
|
||||||
|
- break;
|
||||||
|
- case 4:
|
||||||
|
- val = pcie_read(pcie, RALINK_PCI_PCICFG_ADDR);
|
||||||
|
- val &= ~MT7621_BR_ALL_MASK;
|
||||||
|
- val |= 0x1 << MT7621_BR0_SHIFT;
|
||||||
|
- val |= 0x2 << MT7621_BR1_SHIFT;
|
||||||
|
- val |= 0x0 << MT7621_BR2_SHIFT;
|
||||||
|
- pcie_write(pcie, val, RALINK_PCI_PCICFG_ADDR);
|
||||||
|
- break;
|
||||||
|
- case 5:
|
||||||
|
- val = pcie_read(pcie, RALINK_PCI_PCICFG_ADDR);
|
||||||
|
- val &= ~MT7621_BR_ALL_MASK;
|
||||||
|
- val |= 0x0 << MT7621_BR0_SHIFT;
|
||||||
|
- val |= 0x2 << MT7621_BR1_SHIFT;
|
||||||
|
- val |= 0x1 << MT7621_BR2_SHIFT;
|
||||||
|
- pcie_write(pcie, val, RALINK_PCI_PCICFG_ADDR);
|
||||||
|
- break;
|
||||||
|
- case 6:
|
||||||
|
- val = pcie_read(pcie, RALINK_PCI_PCICFG_ADDR);
|
||||||
|
- val &= ~MT7621_BR_ALL_MASK;
|
||||||
|
- val |= 0x2 << MT7621_BR0_SHIFT;
|
||||||
|
- val |= 0x0 << MT7621_BR1_SHIFT;
|
||||||
|
- val |= 0x1 << MT7621_BR2_SHIFT;
|
||||||
|
- pcie_write(pcie, val, RALINK_PCI_PCICFG_ADDR);
|
||||||
|
- break;
|
||||||
|
- }
|
||||||
|
+ n = 0;
|
||||||
|
+ for (i = 0; i < PCIE_P2P_MAX; i++)
|
||||||
|
+ if (pcie_link_status & BIT(i))
|
||||||
|
+ p2p_br_devnum[i] = n++;
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < PCIE_P2P_MAX; i++)
|
||||||
|
+ if ((pcie_link_status & BIT(i)) == 0)
|
||||||
|
+ p2p_br_devnum[i] = n++;
|
||||||
|
+
|
||||||
|
+ pcie_rmw(pcie, RALINK_PCI_CONFIG_ADDR,
|
||||||
|
+ PCIE_P2P_BR_DEVNUM_MASK_FULL,
|
||||||
|
+ (p2p_br_devnum[0] << PCIE_P2P_BR_DEVNUM0_SHIFT) |
|
||||||
|
+ (p2p_br_devnum[1] << PCIE_P2P_BR_DEVNUM1_SHIFT) |
|
||||||
|
+ (p2p_br_devnum[2] << PCIE_P2P_BR_DEVNUM2_SHIFT));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
From 550fabd71d7fcdfe099bbf41e00e28719737161e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Tue, 10 Mar 2020 12:34:59 +0100
|
||||||
|
Subject: [PATCH] staging: mt7621-pci: enable clock bit for each port
|
||||||
|
|
||||||
|
The clock related code concerns me from the very beginning because
|
||||||
|
there are some set ups got from legacy driver that are not documented
|
||||||
|
anywhere. According to the programming guide 0x7c is 'CPE_ROSC_SEL1'
|
||||||
|
register and 0x80 is 'CPU_CPE_CN'. I do think this set up is not needed
|
||||||
|
at all and the proper thing to do is just enable the clock bit for each
|
||||||
|
pcie port. Hence remove useless code and do the right thing which is
|
||||||
|
setting up the clock bit for each port enabled.
|
||||||
|
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20200310113459.30539-1-sergio.paracuellos@gmail.com
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
---
|
||||||
|
drivers/staging/mt7621-pci/pci-mt7621.c | 17 ++++++-----------
|
||||||
|
1 file changed, 6 insertions(+), 11 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
@@ -45,8 +45,6 @@
|
||||||
|
|
||||||
|
/* rt_sysc_membase relative registers */
|
||||||
|
#define RALINK_CLKCFG1 0x30
|
||||||
|
-#define RALINK_PCIE_CLK_GEN 0x7c
|
||||||
|
-#define RALINK_PCIE_CLK_GEN1 0x80
|
||||||
|
|
||||||
|
/* Host-PCI bridge registers */
|
||||||
|
#define RALINK_PCI_PCICFG_ADDR 0x0000
|
||||||
|
@@ -85,10 +83,6 @@
|
||||||
|
#define PCIE_PORT_CLK_EN(x) BIT(24 + (x))
|
||||||
|
#define PCIE_PORT_LINKUP BIT(0)
|
||||||
|
|
||||||
|
-#define PCIE_CLK_GEN_EN BIT(31)
|
||||||
|
-#define PCIE_CLK_GEN_DIS 0
|
||||||
|
-#define PCIE_CLK_GEN1_DIS GENMASK(30, 24)
|
||||||
|
-#define PCIE_CLK_GEN1_EN (BIT(27) | BIT(25))
|
||||||
|
#define MEMORY_BASE 0x0
|
||||||
|
#define PERST_MODE_MASK GENMASK(11, 10)
|
||||||
|
#define PERST_MODE_GPIO BIT(10)
|
||||||
|
@@ -233,6 +227,11 @@ static inline bool mt7621_pcie_port_is_l
|
||||||
|
return (pcie_port_read(port, RALINK_PCI_STATUS) & PCIE_PORT_LINKUP) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static inline void mt7621_pcie_port_clk_enable(struct mt7621_pcie_port *port)
|
||||||
|
+{
|
||||||
|
+ rt_sysc_m32(0, PCIE_PORT_CLK_EN(port->slot), RALINK_CLKCFG1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static inline void mt7621_pcie_port_clk_disable(struct mt7621_pcie_port *port)
|
||||||
|
{
|
||||||
|
rt_sysc_m32(PCIE_PORT_CLK_EN(port->slot), 0, RALINK_CLKCFG1);
|
||||||
|
@@ -501,11 +500,6 @@ static void mt7621_pcie_init_ports(struc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- rt_sysc_m32(0x30, 2 << 4, SYSC_REG_SYSTEM_CONFIG1);
|
||||||
|
- rt_sysc_m32(PCIE_CLK_GEN_EN, PCIE_CLK_GEN_DIS, RALINK_PCIE_CLK_GEN);
|
||||||
|
- rt_sysc_m32(PCIE_CLK_GEN1_DIS, PCIE_CLK_GEN1_EN, RALINK_PCIE_CLK_GEN1);
|
||||||
|
- rt_sysc_m32(PCIE_CLK_GEN_DIS, PCIE_CLK_GEN_EN, RALINK_PCIE_CLK_GEN);
|
||||||
|
- msleep(50);
|
||||||
|
reset_control_deassert(pcie->rst);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -542,6 +536,7 @@ static void mt7621_pcie_enable_ports(str
|
||||||
|
|
||||||
|
list_for_each_entry(port, &pcie->ports, list) {
|
||||||
|
if (port->enabled) {
|
||||||
|
+ mt7621_pcie_port_clk_enable(port);
|
||||||
|
mt7621_pcie_enable_port(port);
|
||||||
|
dev_info(dev, "PCIE%d enabled\n", num_slots_enabled);
|
||||||
|
num_slots_enabled++;
|
@ -0,0 +1,222 @@
|
|||||||
|
From 227a8bf421ff8b085444e51e471ef06a87228cfd Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Fri, 13 Mar 2020 21:09:08 +0100
|
||||||
|
Subject: [PATCH] staging: mt7621-pci: use gpios for properly reset
|
||||||
|
|
||||||
|
Original driver code was using three gpio's for reset
|
||||||
|
asserts and deasserts the pcis. Instead of using that
|
||||||
|
a general reset control with a perst gpio was introduced
|
||||||
|
and it seems it is partially working but sometimes there
|
||||||
|
are some unexpected hangs on boot. This commit make use of
|
||||||
|
the three original gpios using 'reset-gpios' property of
|
||||||
|
the device tree and removes the reset line and perst gpio.
|
||||||
|
According to the mediatek aplication note v0.1 there are
|
||||||
|
three gpios used for pcie ports reset control: gpio#19,
|
||||||
|
gpio#8 and gpio#7 for slots 0, 1 and 2 respectively.
|
||||||
|
This schema can be used separately for mt7621A but in some
|
||||||
|
boards due to pin share issue, if the PCM and I2S function
|
||||||
|
are enable at the same time, there are no enough GPIO to
|
||||||
|
control per-port PCIe reset. In those cases gpio#19 is enought
|
||||||
|
for reset the three ports together. Because of this we just
|
||||||
|
try to get the three gpios but if some of them fail we are not
|
||||||
|
failing in boot process, just prints a kernel notice and take
|
||||||
|
after into account if the descriptor is or not valid in order
|
||||||
|
to use it. All of them are set as GPIO output low configuration.
|
||||||
|
The gpio descriptor's API takes device tree property into account
|
||||||
|
and invert value if the pin is configured as active low.
|
||||||
|
So we also have to properly request pins from device tree
|
||||||
|
and set values correct in assert and deassert functions.
|
||||||
|
After this changes the order to make all assert and
|
||||||
|
deassert in the 'probe' process makes more sense:
|
||||||
|
* Parse device tree.
|
||||||
|
* make assert of the RC's and EP's before doing anything else.
|
||||||
|
* make deassert of the RC's before initializing the phy.
|
||||||
|
* Init the phy.
|
||||||
|
* make deassert of the EP's before initialize pci ports.
|
||||||
|
* Normal PCI initialization.
|
||||||
|
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20200313200913.24321-2-sergio.paracuellos@gmail.com
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
---
|
||||||
|
drivers/staging/mt7621-pci/pci-mt7621.c | 84 ++++++++++++++++++++-------------
|
||||||
|
1 file changed, 51 insertions(+), 33 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
@@ -95,6 +95,7 @@
|
||||||
|
* @pcie: pointer to PCIe host info
|
||||||
|
* @phy: pointer to PHY control block
|
||||||
|
* @pcie_rst: pointer to port reset control
|
||||||
|
+ * @gpio_rst: gpio reset
|
||||||
|
* @slot: port slot
|
||||||
|
* @enabled: indicates if port is enabled
|
||||||
|
*/
|
||||||
|
@@ -104,6 +105,7 @@ struct mt7621_pcie_port {
|
||||||
|
struct mt7621_pcie *pcie;
|
||||||
|
struct phy *phy;
|
||||||
|
struct reset_control *pcie_rst;
|
||||||
|
+ struct gpio_desc *gpio_rst;
|
||||||
|
u32 slot;
|
||||||
|
bool enabled;
|
||||||
|
};
|
||||||
|
@@ -117,8 +119,6 @@ struct mt7621_pcie_port {
|
||||||
|
* @offset: IO / Memory offset
|
||||||
|
* @dev: Pointer to PCIe device
|
||||||
|
* @ports: pointer to PCIe port information
|
||||||
|
- * @perst: gpio reset
|
||||||
|
- * @rst: pointer to pcie reset
|
||||||
|
* @resets_inverted: depends on chip revision
|
||||||
|
* reset lines are inverted.
|
||||||
|
*/
|
||||||
|
@@ -133,8 +133,6 @@ struct mt7621_pcie {
|
||||||
|
resource_size_t io;
|
||||||
|
} offset;
|
||||||
|
struct list_head ports;
|
||||||
|
- struct gpio_desc *perst;
|
||||||
|
- struct reset_control *rst;
|
||||||
|
bool resets_inverted;
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -210,16 +208,16 @@ static void write_config(struct mt7621_p
|
||||||
|
pcie_write(pcie, val, RALINK_PCI_CONFIG_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
-static inline void mt7621_perst_gpio_pcie_assert(struct mt7621_pcie *pcie)
|
||||||
|
+static inline void mt7621_rst_gpio_pcie_assert(struct mt7621_pcie_port *port)
|
||||||
|
{
|
||||||
|
- gpiod_set_value(pcie->perst, 0);
|
||||||
|
- mdelay(PERST_DELAY_US);
|
||||||
|
+ if (port->gpio_rst)
|
||||||
|
+ gpiod_set_value(port->gpio_rst, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
-static inline void mt7621_perst_gpio_pcie_deassert(struct mt7621_pcie *pcie)
|
||||||
|
+static inline void mt7621_rst_gpio_pcie_deassert(struct mt7621_pcie_port *port)
|
||||||
|
{
|
||||||
|
- gpiod_set_value(pcie->perst, 1);
|
||||||
|
- mdelay(PERST_DELAY_US);
|
||||||
|
+ if (port->gpio_rst)
|
||||||
|
+ gpiod_set_value(port->gpio_rst, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool mt7621_pcie_port_is_linkup(struct mt7621_pcie_port *port)
|
||||||
|
@@ -367,6 +365,13 @@ static int mt7621_pcie_parse_port(struct
|
||||||
|
if (IS_ERR(port->phy))
|
||||||
|
return PTR_ERR(port->phy);
|
||||||
|
|
||||||
|
+ port->gpio_rst = devm_gpiod_get_index_optional(dev, "reset", slot,
|
||||||
|
+ GPIOD_OUT_LOW);
|
||||||
|
+ if (IS_ERR(port->gpio_rst)) {
|
||||||
|
+ dev_err(dev, "Failed to get GPIO for PCIe%d\n", slot);
|
||||||
|
+ return PTR_ERR(port->gpio_rst);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
port->slot = slot;
|
||||||
|
port->pcie = pcie;
|
||||||
|
|
||||||
|
@@ -383,12 +388,6 @@ static int mt7621_pcie_parse_dt(struct m
|
||||||
|
struct resource regs;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
- pcie->perst = devm_gpiod_get(dev, "perst", GPIOD_OUT_HIGH);
|
||||||
|
- if (IS_ERR(pcie->perst)) {
|
||||||
|
- dev_err(dev, "failed to get gpio perst\n");
|
||||||
|
- return PTR_ERR(pcie->perst);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
err = of_address_to_resource(node, 0, ®s);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "missing \"reg\" property\n");
|
||||||
|
@@ -399,12 +398,6 @@ static int mt7621_pcie_parse_dt(struct m
|
||||||
|
if (IS_ERR(pcie->base))
|
||||||
|
return PTR_ERR(pcie->base);
|
||||||
|
|
||||||
|
- pcie->rst = devm_reset_control_get_exclusive(dev, "pcie");
|
||||||
|
- if (PTR_ERR(pcie->rst) == -EPROBE_DEFER) {
|
||||||
|
- dev_err(dev, "failed to get pcie reset control\n");
|
||||||
|
- return PTR_ERR(pcie->rst);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
for_each_available_child_of_node(node, child) {
|
||||||
|
int slot;
|
||||||
|
|
||||||
|
@@ -458,16 +451,49 @@ static int mt7621_pcie_init_port(struct
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void mt7621_pcie_reset_assert(struct mt7621_pcie *pcie)
|
||||||
|
+{
|
||||||
|
+ struct mt7621_pcie_port *port;
|
||||||
|
+
|
||||||
|
+ list_for_each_entry(port, &pcie->ports, list) {
|
||||||
|
+ /* PCIe RC reset assert */
|
||||||
|
+ mt7621_control_assert(port);
|
||||||
|
+
|
||||||
|
+ /* PCIe EP reset assert */
|
||||||
|
+ mt7621_rst_gpio_pcie_assert(port);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ mdelay(PERST_DELAY_US);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void mt7621_pcie_reset_rc_deassert(struct mt7621_pcie *pcie)
|
||||||
|
+{
|
||||||
|
+ struct mt7621_pcie_port *port;
|
||||||
|
+
|
||||||
|
+ list_for_each_entry(port, &pcie->ports, list)
|
||||||
|
+ mt7621_control_deassert(port);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void mt7621_pcie_reset_ep_deassert(struct mt7621_pcie *pcie)
|
||||||
|
+{
|
||||||
|
+ struct mt7621_pcie_port *port;
|
||||||
|
+
|
||||||
|
+ list_for_each_entry(port, &pcie->ports, list)
|
||||||
|
+ mt7621_rst_gpio_pcie_deassert(port);
|
||||||
|
+
|
||||||
|
+ mdelay(PERST_DELAY_US);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
|
||||||
|
{
|
||||||
|
struct device *dev = pcie->dev;
|
||||||
|
struct mt7621_pcie_port *port, *tmp;
|
||||||
|
- u32 val = 0;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
rt_sysc_m32(PERST_MODE_MASK, PERST_MODE_GPIO, MT7621_GPIO_MODE);
|
||||||
|
|
||||||
|
- mt7621_perst_gpio_pcie_assert(pcie);
|
||||||
|
+ mt7621_pcie_reset_assert(pcie);
|
||||||
|
+ mt7621_pcie_reset_rc_deassert(pcie);
|
||||||
|
|
||||||
|
list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
|
||||||
|
u32 slot = port->slot;
|
||||||
|
@@ -476,16 +502,10 @@ static void mt7621_pcie_init_ports(struc
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "Initiating port %d failed\n", slot);
|
||||||
|
list_del(&port->list);
|
||||||
|
- } else {
|
||||||
|
- val = read_config(pcie, slot, PCIE_FTS_NUM);
|
||||||
|
- dev_info(dev, "Port %d N_FTS = %x\n", slot,
|
||||||
|
- (unsigned int)val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- reset_control_assert(pcie->rst);
|
||||||
|
-
|
||||||
|
- mt7621_perst_gpio_pcie_deassert(pcie);
|
||||||
|
+ mt7621_pcie_reset_ep_deassert(pcie);
|
||||||
|
|
||||||
|
list_for_each_entry(port, &pcie->ports, list) {
|
||||||
|
u32 slot = port->slot;
|
||||||
|
@@ -499,8 +519,6 @@ static void mt7621_pcie_init_ports(struc
|
||||||
|
port->enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
-
|
||||||
|
- reset_control_deassert(pcie->rst);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mt7621_pcie_enable_port(struct mt7621_pcie_port *port)
|
@ -0,0 +1,45 @@
|
|||||||
|
From e462e7d3211479df42357a620fa788a2257556b7 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Fri, 13 Mar 2020 21:09:09 +0100
|
||||||
|
Subject: [PATCH] staging: mt7621-pci: change value for 'PERST_DELAY_MS'
|
||||||
|
|
||||||
|
Value of 'PERST_DELAY_MS' is too high and it is ok just
|
||||||
|
to set up to 100 ms. Update also define name from
|
||||||
|
'PERST_DELAY_US' into 'PERST_DELAY_MS'
|
||||||
|
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20200313200913.24321-3-sergio.paracuellos@gmail.com
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
---
|
||||||
|
drivers/staging/mt7621-pci/pci-mt7621.c | 6 +++---
|
||||||
|
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
@@ -86,7 +86,7 @@
|
||||||
|
#define MEMORY_BASE 0x0
|
||||||
|
#define PERST_MODE_MASK GENMASK(11, 10)
|
||||||
|
#define PERST_MODE_GPIO BIT(10)
|
||||||
|
-#define PERST_DELAY_US 1000
|
||||||
|
+#define PERST_DELAY_MS 100
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct mt7621_pcie_port - PCIe port information
|
||||||
|
@@ -463,7 +463,7 @@ static void mt7621_pcie_reset_assert(str
|
||||||
|
mt7621_rst_gpio_pcie_assert(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
- mdelay(PERST_DELAY_US);
|
||||||
|
+ mdelay(PERST_DELAY_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mt7621_pcie_reset_rc_deassert(struct mt7621_pcie *pcie)
|
||||||
|
@@ -481,7 +481,7 @@ static void mt7621_pcie_reset_ep_deasser
|
||||||
|
list_for_each_entry(port, &pcie->ports, list)
|
||||||
|
mt7621_rst_gpio_pcie_deassert(port);
|
||||||
|
|
||||||
|
- mdelay(PERST_DELAY_US);
|
||||||
|
+ mdelay(PERST_DELAY_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
|
@ -0,0 +1,76 @@
|
|||||||
|
From 4d6a758f2cd2122a7d895f913854c13da62ba6df Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Fri, 13 Mar 2020 21:09:12 +0100
|
||||||
|
Subject: [PATCH] staging: mt7621-pci: release gpios after pci initialization
|
||||||
|
|
||||||
|
R3G's LEDs fail to initialize because one of them uses GPIO8
|
||||||
|
Hence, release the GPIO resources after PCIe initialization
|
||||||
|
and properly release also in driver error path.
|
||||||
|
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20200313200913.24321-6-sergio.paracuellos@gmail.com
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
---
|
||||||
|
drivers/staging/mt7621-pci/pci-mt7621.c | 23 ++++++++++++++++++-----
|
||||||
|
1 file changed, 18 insertions(+), 5 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
@@ -484,6 +484,15 @@ static void mt7621_pcie_reset_ep_deasser
|
||||||
|
mdelay(PERST_DELAY_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void mt7621_pcie_release_gpios(struct mt7621_pcie *pcie)
|
||||||
|
+{
|
||||||
|
+ struct mt7621_pcie_port *port;
|
||||||
|
+
|
||||||
|
+ list_for_each_entry(port, &pcie->ports, list)
|
||||||
|
+ if (port->gpio_rst)
|
||||||
|
+ gpiod_put(port->gpio_rst);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
|
||||||
|
{
|
||||||
|
struct device *dev = pcie->dev;
|
||||||
|
@@ -683,7 +692,8 @@ static int mt7621_pci_probe(struct platf
|
||||||
|
err = mt7621_pcie_init_virtual_bridges(pcie);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "Nothing is connected in virtual bridges. Exiting...");
|
||||||
|
- return 0;
|
||||||
|
+ err = 0;
|
||||||
|
+ goto out_release_gpios;
|
||||||
|
}
|
||||||
|
|
||||||
|
mt7621_pcie_enable_ports(pcie);
|
||||||
|
@@ -691,7 +701,7 @@ static int mt7621_pci_probe(struct platf
|
||||||
|
err = mt7621_pci_parse_request_of_pci_ranges(pcie);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "Error requesting pci resources from ranges");
|
||||||
|
- return err;
|
||||||
|
+ goto out_release_gpios;
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_cm_memory_region(pcie);
|
||||||
|
@@ -699,16 +709,19 @@ static int mt7621_pci_probe(struct platf
|
||||||
|
err = mt7621_pcie_request_resources(pcie, &res);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "Error requesting resources\n");
|
||||||
|
- return err;
|
||||||
|
+ goto out_release_gpios;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = mt7621_pcie_register_host(bridge, &res);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "Error registering host\n");
|
||||||
|
- return err;
|
||||||
|
+ goto out_release_gpios;
|
||||||
|
}
|
||||||
|
|
||||||
|
- return 0;
|
||||||
|
+out_release_gpios:
|
||||||
|
+ mt7621_pcie_release_gpios(pcie);
|
||||||
|
+
|
||||||
|
+ return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id mt7621_pci_ids[] = {
|
@ -0,0 +1,46 @@
|
|||||||
|
From 4be54c3a495f08c05a8e485566e5b88cd3537f16 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Fri, 13 Mar 2020 21:09:13 +0100
|
||||||
|
Subject: [PATCH] staging: mt7621-pci: delete no more needed
|
||||||
|
'mt7621_reset_port'
|
||||||
|
|
||||||
|
After review all the resets at the beggining the function
|
||||||
|
'mt7621_reset_port' is not needed anymore. Hence delete it
|
||||||
|
and its uses.
|
||||||
|
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20200313200913.24321-7-sergio.paracuellos@gmail.com
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
---
|
||||||
|
drivers/staging/mt7621-pci/pci-mt7621.c | 13 -------------
|
||||||
|
1 file changed, 13 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
@@ -255,13 +255,6 @@ static inline void mt7621_control_deasse
|
||||||
|
reset_control_assert(port->pcie_rst);
|
||||||
|
}
|
||||||
|
|
||||||
|
-static void mt7621_reset_port(struct mt7621_pcie_port *port)
|
||||||
|
-{
|
||||||
|
- mt7621_control_assert(port);
|
||||||
|
- msleep(100);
|
||||||
|
- mt7621_control_deassert(port);
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
static void setup_cm_memory_region(struct mt7621_pcie *pcie)
|
||||||
|
{
|
||||||
|
struct resource *mem_resource = &pcie->mem;
|
||||||
|
@@ -427,12 +420,6 @@ static int mt7621_pcie_init_port(struct
|
||||||
|
u32 slot = port->slot;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
- /*
|
||||||
|
- * Any MT7621 Ralink pcie controller that doesn't have 0x0101 at
|
||||||
|
- * the end of the chip_id has inverted PCI resets.
|
||||||
|
- */
|
||||||
|
- mt7621_reset_port(port);
|
||||||
|
-
|
||||||
|
err = phy_init(port->phy);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "failed to initialize port%d phy\n", slot);
|
@ -0,0 +1,234 @@
|
|||||||
|
From bf0c6782e5b9a6deee4e223655325dc004fae8dd Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Sun, 15 Mar 2020 17:01:54 +0100
|
||||||
|
Subject: [PATCH] staging: mt7621-pci-phy: add 'mt7621_phy_rmw' to simplify
|
||||||
|
code
|
||||||
|
|
||||||
|
In order to simplify driver code and decrease a bit LOC add new
|
||||||
|
function 'mt7621_phy_rmw' where clear and set bits are passed as
|
||||||
|
arguments.
|
||||||
|
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20200315160154.10292-1-sergio.paracuellos@gmail.com
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
---
|
||||||
|
drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c | 158 +++++++++++-------------
|
||||||
|
1 file changed, 71 insertions(+), 87 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c
|
||||||
|
+++ b/drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c
|
||||||
|
@@ -120,17 +120,25 @@ static inline void phy_write(struct mt76
|
||||||
|
regmap_write(phy->regmap, reg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static inline void mt7621_phy_rmw(struct mt7621_pci_phy *phy,
|
||||||
|
+ u32 reg, u32 clr, u32 set)
|
||||||
|
+{
|
||||||
|
+ u32 val = phy_read(phy, reg);
|
||||||
|
+
|
||||||
|
+ val &= ~clr;
|
||||||
|
+ val |= set;
|
||||||
|
+ phy_write(phy, val, reg);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void mt7621_bypass_pipe_rst(struct mt7621_pci_phy *phy,
|
||||||
|
struct mt7621_pci_phy_instance *instance)
|
||||||
|
{
|
||||||
|
u32 offset = (instance->index != 1) ?
|
||||||
|
RG_PE1_PIPE_REG : RG_PE1_PIPE_REG + RG_P0_TO_P1_WIDTH;
|
||||||
|
- u32 reg;
|
||||||
|
|
||||||
|
- reg = phy_read(phy, offset);
|
||||||
|
- reg &= ~(RG_PE1_PIPE_RST | RG_PE1_PIPE_CMD_FRC);
|
||||||
|
- reg |= (RG_PE1_PIPE_RST | RG_PE1_PIPE_CMD_FRC);
|
||||||
|
- phy_write(phy, reg, offset);
|
||||||
|
+ mt7621_phy_rmw(phy, offset,
|
||||||
|
+ RG_PE1_PIPE_RST | RG_PE1_PIPE_CMD_FRC,
|
||||||
|
+ RG_PE1_PIPE_RST | RG_PE1_PIPE_CMD_FRC);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mt7621_set_phy_for_ssc(struct mt7621_pci_phy *phy,
|
||||||
|
@@ -139,97 +147,77 @@ static void mt7621_set_phy_for_ssc(struc
|
||||||
|
struct device *dev = phy->dev;
|
||||||
|
u32 reg = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0);
|
||||||
|
u32 offset;
|
||||||
|
- u32 val;
|
||||||
|
|
||||||
|
reg = (reg >> 6) & 0x7;
|
||||||
|
/* Set PCIe Port PHY to disable SSC */
|
||||||
|
/* Debug Xtal Type */
|
||||||
|
- val = phy_read(phy, RG_PE1_FRC_H_XTAL_REG);
|
||||||
|
- val &= ~(RG_PE1_FRC_H_XTAL_TYPE | RG_PE1_H_XTAL_TYPE);
|
||||||
|
- val |= RG_PE1_FRC_H_XTAL_TYPE;
|
||||||
|
- val |= RG_PE1_H_XTAL_TYPE_VAL(0x00);
|
||||||
|
- phy_write(phy, val, RG_PE1_FRC_H_XTAL_REG);
|
||||||
|
+ mt7621_phy_rmw(phy, RG_PE1_FRC_H_XTAL_REG,
|
||||||
|
+ RG_PE1_FRC_H_XTAL_TYPE | RG_PE1_H_XTAL_TYPE,
|
||||||
|
+ RG_PE1_FRC_H_XTAL_TYPE | RG_PE1_H_XTAL_TYPE_VAL(0x00));
|
||||||
|
|
||||||
|
/* disable port */
|
||||||
|
offset = (instance->index != 1) ?
|
||||||
|
RG_PE1_FRC_PHY_REG : RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH;
|
||||||
|
- val = phy_read(phy, offset);
|
||||||
|
- val &= ~(RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN);
|
||||||
|
- val |= RG_PE1_FRC_PHY_EN;
|
||||||
|
- phy_write(phy, val, offset);
|
||||||
|
-
|
||||||
|
- /* Set Pre-divider ratio (for host mode) */
|
||||||
|
- val = phy_read(phy, RG_PE1_H_PLL_REG);
|
||||||
|
- val &= ~(RG_PE1_H_PLL_PREDIV);
|
||||||
|
+ mt7621_phy_rmw(phy, offset,
|
||||||
|
+ RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN);
|
||||||
|
|
||||||
|
if (reg <= 5 && reg >= 3) { /* 40MHz Xtal */
|
||||||
|
- val |= RG_PE1_H_PLL_PREDIV_VAL(0x01);
|
||||||
|
- phy_write(phy, val, RG_PE1_H_PLL_REG);
|
||||||
|
+ /* Set Pre-divider ratio (for host mode) */
|
||||||
|
+ mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG,
|
||||||
|
+ RG_PE1_H_PLL_PREDIV,
|
||||||
|
+ RG_PE1_H_PLL_PREDIV_VAL(0x01));
|
||||||
|
dev_info(dev, "Xtal is 40MHz\n");
|
||||||
|
- } else { /* 25MHz | 20MHz Xtal */
|
||||||
|
- val |= RG_PE1_H_PLL_PREDIV_VAL(0x00);
|
||||||
|
- phy_write(phy, val, RG_PE1_H_PLL_REG);
|
||||||
|
- if (reg >= 6) {
|
||||||
|
- dev_info(dev, "Xtal is 25MHz\n");
|
||||||
|
-
|
||||||
|
- /* Select feedback clock */
|
||||||
|
- val = phy_read(phy, RG_PE1_H_PLL_FBKSEL_REG);
|
||||||
|
- val &= ~(RG_PE1_H_PLL_FBKSEL);
|
||||||
|
- val |= RG_PE1_H_PLL_FBKSEL_VAL(0x01);
|
||||||
|
- phy_write(phy, val, RG_PE1_H_PLL_FBKSEL_REG);
|
||||||
|
-
|
||||||
|
- /* DDS NCPO PCW (for host mode) */
|
||||||
|
- val = phy_read(phy, RG_PE1_H_LCDDS_SSC_PRD_REG);
|
||||||
|
- val &= ~(RG_PE1_H_LCDDS_SSC_PRD);
|
||||||
|
- val |= RG_PE1_H_LCDDS_SSC_PRD_VAL(0x18000000);
|
||||||
|
- phy_write(phy, val, RG_PE1_H_LCDDS_SSC_PRD_REG);
|
||||||
|
-
|
||||||
|
- /* DDS SSC dither period control */
|
||||||
|
- val = phy_read(phy, RG_PE1_H_LCDDS_SSC_PRD_REG);
|
||||||
|
- val &= ~(RG_PE1_H_LCDDS_SSC_PRD);
|
||||||
|
- val |= RG_PE1_H_LCDDS_SSC_PRD_VAL(0x18d);
|
||||||
|
- phy_write(phy, val, RG_PE1_H_LCDDS_SSC_PRD_REG);
|
||||||
|
-
|
||||||
|
- /* DDS SSC dither amplitude control */
|
||||||
|
- val = phy_read(phy, RG_PE1_H_LCDDS_SSC_DELTA_REG);
|
||||||
|
- val &= ~(RG_PE1_H_LCDDS_SSC_DELTA |
|
||||||
|
- RG_PE1_H_LCDDS_SSC_DELTA1);
|
||||||
|
- val |= RG_PE1_H_LCDDS_SSC_DELTA_VAL(0x4a);
|
||||||
|
- val |= RG_PE1_H_LCDDS_SSC_DELTA1_VAL(0x4a);
|
||||||
|
- phy_write(phy, val, RG_PE1_H_LCDDS_SSC_DELTA_REG);
|
||||||
|
- } else {
|
||||||
|
- dev_info(dev, "Xtal is 20MHz\n");
|
||||||
|
- }
|
||||||
|
+ } else if (reg >= 6) { /* 25MHz Xal */
|
||||||
|
+ mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG,
|
||||||
|
+ RG_PE1_H_PLL_PREDIV,
|
||||||
|
+ RG_PE1_H_PLL_PREDIV_VAL(0x00));
|
||||||
|
+ /* Select feedback clock */
|
||||||
|
+ mt7621_phy_rmw(phy, RG_PE1_H_PLL_FBKSEL_REG,
|
||||||
|
+ RG_PE1_H_PLL_FBKSEL,
|
||||||
|
+ RG_PE1_H_PLL_FBKSEL_VAL(0x01));
|
||||||
|
+ /* DDS NCPO PCW (for host mode) */
|
||||||
|
+ mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_PRD_REG,
|
||||||
|
+ RG_PE1_H_LCDDS_SSC_PRD,
|
||||||
|
+ RG_PE1_H_LCDDS_SSC_PRD_VAL(0x18000000));
|
||||||
|
+ /* DDS SSC dither period control */
|
||||||
|
+ mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_PRD_REG,
|
||||||
|
+ RG_PE1_H_LCDDS_SSC_PRD,
|
||||||
|
+ RG_PE1_H_LCDDS_SSC_PRD_VAL(0x18d));
|
||||||
|
+ /* DDS SSC dither amplitude control */
|
||||||
|
+ mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_DELTA_REG,
|
||||||
|
+ RG_PE1_H_LCDDS_SSC_DELTA |
|
||||||
|
+ RG_PE1_H_LCDDS_SSC_DELTA1,
|
||||||
|
+ RG_PE1_H_LCDDS_SSC_DELTA_VAL(0x4a) |
|
||||||
|
+ RG_PE1_H_LCDDS_SSC_DELTA1_VAL(0x4a));
|
||||||
|
+ dev_info(dev, "Xtal is 25MHz\n");
|
||||||
|
+ } else { /* 20MHz Xtal */
|
||||||
|
+ mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG,
|
||||||
|
+ RG_PE1_H_PLL_PREDIV,
|
||||||
|
+ RG_PE1_H_PLL_PREDIV_VAL(0x00));
|
||||||
|
+
|
||||||
|
+ dev_info(dev, "Xtal is 20MHz\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* DDS clock inversion */
|
||||||
|
- val = phy_read(phy, RG_PE1_LCDDS_CLK_PH_INV_REG);
|
||||||
|
- val &= ~(RG_PE1_LCDDS_CLK_PH_INV);
|
||||||
|
- val |= RG_PE1_LCDDS_CLK_PH_INV;
|
||||||
|
- phy_write(phy, val, RG_PE1_LCDDS_CLK_PH_INV_REG);
|
||||||
|
+ mt7621_phy_rmw(phy, RG_PE1_LCDDS_CLK_PH_INV_REG,
|
||||||
|
+ RG_PE1_LCDDS_CLK_PH_INV, RG_PE1_LCDDS_CLK_PH_INV);
|
||||||
|
|
||||||
|
/* Set PLL bits */
|
||||||
|
- val = phy_read(phy, RG_PE1_H_PLL_REG);
|
||||||
|
- val &= ~(RG_PE1_H_PLL_BC | RG_PE1_H_PLL_BP | RG_PE1_H_PLL_IR |
|
||||||
|
- RG_PE1_H_PLL_IC | RG_PE1_PLL_DIVEN);
|
||||||
|
- val |= RG_PE1_H_PLL_BC_VAL(0x02);
|
||||||
|
- val |= RG_PE1_H_PLL_BP_VAL(0x06);
|
||||||
|
- val |= RG_PE1_H_PLL_IR_VAL(0x02);
|
||||||
|
- val |= RG_PE1_H_PLL_IC_VAL(0x01);
|
||||||
|
- val |= RG_PE1_PLL_DIVEN_VAL(0x02);
|
||||||
|
- phy_write(phy, val, RG_PE1_H_PLL_REG);
|
||||||
|
-
|
||||||
|
- val = phy_read(phy, RG_PE1_H_PLL_BR_REG);
|
||||||
|
- val &= ~(RG_PE1_H_PLL_BR);
|
||||||
|
- val |= RG_PE1_H_PLL_BR_VAL(0x00);
|
||||||
|
- phy_write(phy, val, RG_PE1_H_PLL_BR_REG);
|
||||||
|
+ mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG,
|
||||||
|
+ RG_PE1_H_PLL_BC | RG_PE1_H_PLL_BP | RG_PE1_H_PLL_IR |
|
||||||
|
+ RG_PE1_H_PLL_IC | RG_PE1_PLL_DIVEN,
|
||||||
|
+ RG_PE1_H_PLL_BC_VAL(0x02) | RG_PE1_H_PLL_BP_VAL(0x06) |
|
||||||
|
+ RG_PE1_H_PLL_IR_VAL(0x02) | RG_PE1_H_PLL_IC_VAL(0x01) |
|
||||||
|
+ RG_PE1_PLL_DIVEN_VAL(0x02));
|
||||||
|
+
|
||||||
|
+ mt7621_phy_rmw(phy, RG_PE1_H_PLL_BR_REG,
|
||||||
|
+ RG_PE1_H_PLL_BR, RG_PE1_H_PLL_BR_VAL(0x00));
|
||||||
|
|
||||||
|
if (reg <= 5 && reg >= 3) { /* 40MHz Xtal */
|
||||||
|
/* set force mode enable of da_pe1_mstckdiv */
|
||||||
|
- val = phy_read(phy, RG_PE1_MSTCKDIV_REG);
|
||||||
|
- val &= ~(RG_PE1_MSTCKDIV | RG_PE1_FRC_MSTCKDIV);
|
||||||
|
- val |= (RG_PE1_MSTCKDIV_VAL(0x01) | RG_PE1_FRC_MSTCKDIV);
|
||||||
|
- phy_write(phy, val, RG_PE1_MSTCKDIV_REG);
|
||||||
|
+ mt7621_phy_rmw(phy, RG_PE1_MSTCKDIV_REG,
|
||||||
|
+ RG_PE1_MSTCKDIV | RG_PE1_FRC_MSTCKDIV,
|
||||||
|
+ RG_PE1_MSTCKDIV_VAL(0x01) | RG_PE1_FRC_MSTCKDIV);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -252,13 +240,11 @@ static int mt7621_pci_phy_power_on(struc
|
||||||
|
struct mt7621_pci_phy *mphy = dev_get_drvdata(phy->dev.parent);
|
||||||
|
u32 offset = (instance->index != 1) ?
|
||||||
|
RG_PE1_FRC_PHY_REG : RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH;
|
||||||
|
- u32 val;
|
||||||
|
|
||||||
|
/* Enable PHY and disable force mode */
|
||||||
|
- val = phy_read(mphy, offset);
|
||||||
|
- val &= ~(RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN);
|
||||||
|
- val |= (RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN);
|
||||||
|
- phy_write(mphy, val, offset);
|
||||||
|
+ mt7621_phy_rmw(mphy, offset,
|
||||||
|
+ RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN,
|
||||||
|
+ RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@@ -269,13 +255,11 @@ static int mt7621_pci_phy_power_off(stru
|
||||||
|
struct mt7621_pci_phy *mphy = dev_get_drvdata(phy->dev.parent);
|
||||||
|
u32 offset = (instance->index != 1) ?
|
||||||
|
RG_PE1_FRC_PHY_REG : RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH;
|
||||||
|
- u32 val;
|
||||||
|
|
||||||
|
/* Disable PHY */
|
||||||
|
- val = phy_read(mphy, offset);
|
||||||
|
- val &= ~(RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN);
|
||||||
|
- val |= RG_PE1_FRC_PHY_EN;
|
||||||
|
- phy_write(mphy, val, offset);
|
||||||
|
+ mt7621_phy_rmw(mphy, offset,
|
||||||
|
+ RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN,
|
||||||
|
+ RG_PE1_FRC_PHY_EN);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,131 @@
|
|||||||
|
From 3faf4e1c537de86058fc22a851cd979489b9185e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Wed, 18 Mar 2020 10:44:45 +0100
|
||||||
|
Subject: [PATCH] staging: mt7621-pci: fix io space and properly set resource
|
||||||
|
limits
|
||||||
|
|
||||||
|
Function 'mt7621_pci_parse_request_of_pci_ranges' is using
|
||||||
|
'of_pci_range_to_resource' to get both mem and io resources.
|
||||||
|
Internally this function calls to 'pci_address_to_pio' which
|
||||||
|
returns -1 if io space address is an address > IO_SPACE_LIMIT
|
||||||
|
which is 0xFFFF for mips. This mt7621 soc has io space in physical
|
||||||
|
address 0x1e160000. In order to fix this, overwrite invalid io
|
||||||
|
0xffffffff with properly values from the device tree and set
|
||||||
|
mapped address of this resource as io port base memory address
|
||||||
|
calling 'set_io_port_base' function. There is also need to properly
|
||||||
|
setup resource limits and io and memory windows with properly
|
||||||
|
parsed values instead of set them as 'no limit' which it is wrong.
|
||||||
|
For any reason I don't really know legacy driver sets up mem window
|
||||||
|
as 0xFFFFFFFF and any other value seems to does not work as expected,
|
||||||
|
so set up also here with same values.
|
||||||
|
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20200318094445.19669-1-sergio.paracuellos@gmail.com
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
---
|
||||||
|
drivers/staging/mt7621-pci/pci-mt7621.c | 43 +++++++++++++++++++--------------
|
||||||
|
1 file changed, 25 insertions(+), 18 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
@@ -118,6 +118,7 @@ struct mt7621_pcie_port {
|
||||||
|
* @busn: bus range
|
||||||
|
* @offset: IO / Memory offset
|
||||||
|
* @dev: Pointer to PCIe device
|
||||||
|
+ * @io_map_base: virtual memory base address for io
|
||||||
|
* @ports: pointer to PCIe port information
|
||||||
|
* @resets_inverted: depends on chip revision
|
||||||
|
* reset lines are inverted.
|
||||||
|
@@ -132,6 +133,7 @@ struct mt7621_pcie {
|
||||||
|
resource_size_t mem;
|
||||||
|
resource_size_t io;
|
||||||
|
} offset;
|
||||||
|
+ unsigned long io_map_base;
|
||||||
|
struct list_head ports;
|
||||||
|
bool resets_inverted;
|
||||||
|
};
|
||||||
|
@@ -291,22 +293,21 @@ static int mt7621_pci_parse_request_of_p
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_of_pci_range(&parser, &range) {
|
||||||
|
- struct resource *res = NULL;
|
||||||
|
-
|
||||||
|
switch (range.flags & IORESOURCE_TYPE_BITS) {
|
||||||
|
case IORESOURCE_IO:
|
||||||
|
- ioremap(range.cpu_addr, range.size);
|
||||||
|
- res = &pcie->io;
|
||||||
|
+ pcie->io_map_base =
|
||||||
|
+ (unsigned long)ioremap(range.cpu_addr,
|
||||||
|
+ range.size);
|
||||||
|
+ of_pci_range_to_resource(&range, node, &pcie->io);
|
||||||
|
+ pcie->io.start = range.cpu_addr;
|
||||||
|
+ pcie->io.end = range.cpu_addr + range.size - 1;
|
||||||
|
pcie->offset.io = 0x00000000UL;
|
||||||
|
break;
|
||||||
|
case IORESOURCE_MEM:
|
||||||
|
- res = &pcie->mem;
|
||||||
|
+ of_pci_range_to_resource(&range, node, &pcie->mem);
|
||||||
|
pcie->offset.mem = 0x00000000UL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
-
|
||||||
|
- if (res)
|
||||||
|
- of_pci_range_to_resource(&range, node, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = of_pci_parse_bus_range(node, &pcie->busn);
|
||||||
|
@@ -318,6 +319,8 @@ static int mt7621_pci_parse_request_of_p
|
||||||
|
pcie->busn.flags = IORESOURCE_BUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ set_io_port_base(pcie->io_map_base);
|
||||||
|
+
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -548,6 +551,10 @@ static void mt7621_pcie_enable_ports(str
|
||||||
|
u32 slot;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
+ /* Setup MEMWIN and IOWIN */
|
||||||
|
+ pcie_write(pcie, 0xffffffff, RALINK_PCI_MEMBASE);
|
||||||
|
+ pcie_write(pcie, pcie->io.start, RALINK_PCI_IOBASE);
|
||||||
|
+
|
||||||
|
list_for_each_entry(port, &pcie->ports, list) {
|
||||||
|
if (port->enabled) {
|
||||||
|
mt7621_pcie_port_clk_enable(port);
|
||||||
|
@@ -668,11 +675,17 @@ static int mt7621_pci_probe(struct platf
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ err = mt7621_pci_parse_request_of_pci_ranges(pcie);
|
||||||
|
+ if (err) {
|
||||||
|
+ dev_err(dev, "Error requesting pci resources from ranges");
|
||||||
|
+ goto out_release_gpios;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
/* set resources limits */
|
||||||
|
- iomem_resource.start = 0;
|
||||||
|
- iomem_resource.end = ~0UL; /* no limit */
|
||||||
|
- ioport_resource.start = 0;
|
||||||
|
- ioport_resource.end = ~0UL; /* no limit */
|
||||||
|
+ iomem_resource.start = pcie->mem.start;
|
||||||
|
+ iomem_resource.end = pcie->mem.end;
|
||||||
|
+ ioport_resource.start = pcie->io.start;
|
||||||
|
+ ioport_resource.end = pcie->io.end;
|
||||||
|
|
||||||
|
mt7621_pcie_init_ports(pcie);
|
||||||
|
|
||||||
|
@@ -685,12 +698,6 @@ static int mt7621_pci_probe(struct platf
|
||||||
|
|
||||||
|
mt7621_pcie_enable_ports(pcie);
|
||||||
|
|
||||||
|
- err = mt7621_pci_parse_request_of_pci_ranges(pcie);
|
||||||
|
- if (err) {
|
||||||
|
- dev_err(dev, "Error requesting pci resources from ranges");
|
||||||
|
- goto out_release_gpios;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
setup_cm_memory_region(pcie);
|
||||||
|
|
||||||
|
err = mt7621_pcie_request_resources(pcie, &res);
|
@ -0,0 +1,28 @@
|
|||||||
|
From 0a3085ae142d8f5cf905b104bc66db3721a2fa33 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Thu, 19 Mar 2020 10:57:33 +0100
|
||||||
|
Subject: [PATCH] staging: mt7621-pci: fix register to set up virtual bridges
|
||||||
|
|
||||||
|
Instead of being using PCI Configuration and Status Register to
|
||||||
|
set up virtual bridges we are using CONFIG_ADDR Register which is
|
||||||
|
wrong. Hence, set the correct value.
|
||||||
|
|
||||||
|
Fixes: 9a5e71a68d20 ("staging: mt7621-pci: simplify 'mt7621_pcie_init_virtual_bridges' function")
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20200319095733.1557-1-sergio.paracuellos@gmail.com
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
---
|
||||||
|
drivers/staging/mt7621-pci/pci-mt7621.c | 2 +-
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
@@ -603,7 +603,7 @@ static int mt7621_pcie_init_virtual_brid
|
||||||
|
if ((pcie_link_status & BIT(i)) == 0)
|
||||||
|
p2p_br_devnum[i] = n++;
|
||||||
|
|
||||||
|
- pcie_rmw(pcie, RALINK_PCI_CONFIG_ADDR,
|
||||||
|
+ pcie_rmw(pcie, RALINK_PCI_PCICFG_ADDR,
|
||||||
|
PCIE_P2P_BR_DEVNUM_MASK_FULL,
|
||||||
|
(p2p_br_devnum[0] << PCIE_P2P_BR_DEVNUM0_SHIFT) |
|
||||||
|
(p2p_br_devnum[1] << PCIE_P2P_BR_DEVNUM1_SHIFT) |
|
@ -0,0 +1,34 @@
|
|||||||
|
From 23a788c23ed10e0d79092fcb693dcf0e357e1f7e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Thu, 19 Mar 2020 17:14:16 +0100
|
||||||
|
Subject: [PATCH] staging: mt7621-pci: don't return if get gpio fails
|
||||||
|
|
||||||
|
In some platforms gpio's are not used for reset but
|
||||||
|
for other purposes. Because of that when we try to
|
||||||
|
get them are valid gpio's but are already assigned
|
||||||
|
to do other function. To avoid those kind of problems
|
||||||
|
in those platforms just notice the fail in the kernel
|
||||||
|
but continue doing normal boot.
|
||||||
|
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20200319161416.19033-1-sergio.paracuellos@gmail.com
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
---
|
||||||
|
drivers/staging/mt7621-pci/pci-mt7621.c | 6 ++----
|
||||||
|
1 file changed, 2 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
@@ -363,10 +363,8 @@ static int mt7621_pcie_parse_port(struct
|
||||||
|
|
||||||
|
port->gpio_rst = devm_gpiod_get_index_optional(dev, "reset", slot,
|
||||||
|
GPIOD_OUT_LOW);
|
||||||
|
- if (IS_ERR(port->gpio_rst)) {
|
||||||
|
- dev_err(dev, "Failed to get GPIO for PCIe%d\n", slot);
|
||||||
|
- return PTR_ERR(port->gpio_rst);
|
||||||
|
- }
|
||||||
|
+ if (IS_ERR(port->gpio_rst))
|
||||||
|
+ dev_notice(dev, "Failed to get GPIO for PCIe%d\n", slot);
|
||||||
|
|
||||||
|
port->slot = slot;
|
||||||
|
port->pcie = pcie;
|
@ -0,0 +1,272 @@
|
|||||||
|
From 91eb47531421f0e8c9bc4594b4a7caa0e59dc83e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Fri, 20 Mar 2020 12:01:19 +0100
|
||||||
|
Subject: [PATCH] staging: mt7621-pci-phy: avoid to create to different phys
|
||||||
|
for a dual port one
|
||||||
|
|
||||||
|
This soc has two phy's for the pcie one of them using just a different
|
||||||
|
register for settig it up but sharing all the rest of the config. Until
|
||||||
|
now we was presenting this schema as three different phy's in the device
|
||||||
|
tree using the 'phy-cells' node property to discriminate an index and
|
||||||
|
setting up a complete phy for the dual port index. This sometimes worked
|
||||||
|
properly but reconfiguring the same registers twice presents sometimes
|
||||||
|
some unstable pcie links and the ports was not properly being detected.
|
||||||
|
The problems only appears on hard resets and soft resets was properly
|
||||||
|
working. Instead of having this schema just set two phy's in the device
|
||||||
|
ree and use the 'phy-cells' property to say if the port has or not a dual
|
||||||
|
port. Doing this configuration and set up becomes easier, LOC is decreased
|
||||||
|
and the behaviour also gets deterministic with properly and stable pcie
|
||||||
|
links in both hard and soft resets.
|
||||||
|
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20200320110123.9907-2-sergio.paracuellos@gmail.com
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
---
|
||||||
|
drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c | 144 ++++++++++--------------
|
||||||
|
1 file changed, 59 insertions(+), 85 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c
|
||||||
|
+++ b/drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c
|
||||||
|
@@ -78,31 +78,21 @@
|
||||||
|
#define MAX_PHYS 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
- * struct mt7621_pci_phy_instance - Mt7621 Pcie PHY device
|
||||||
|
- * @phy: pointer to the kernel PHY device
|
||||||
|
- * @port_base: base register
|
||||||
|
- * @index: internal ID to identify the Mt7621 PCIe PHY
|
||||||
|
- */
|
||||||
|
-struct mt7621_pci_phy_instance {
|
||||||
|
- struct phy *phy;
|
||||||
|
- void __iomem *port_base;
|
||||||
|
- u32 index;
|
||||||
|
-};
|
||||||
|
-
|
||||||
|
-/**
|
||||||
|
* struct mt7621_pci_phy - Mt7621 Pcie PHY core
|
||||||
|
* @dev: pointer to device
|
||||||
|
* @regmap: kernel regmap pointer
|
||||||
|
- * @phys: pointer to Mt7621 PHY device
|
||||||
|
- * @nphys: number of PHY devices for this core
|
||||||
|
+ * @phy: pointer to the kernel PHY device
|
||||||
|
+ * @port_base: base register
|
||||||
|
+ * @has_dual_port: if the phy has dual ports.
|
||||||
|
* @bypass_pipe_rst: mark if 'mt7621_bypass_pipe_rst'
|
||||||
|
* needs to be executed. Depends on chip revision.
|
||||||
|
*/
|
||||||
|
struct mt7621_pci_phy {
|
||||||
|
struct device *dev;
|
||||||
|
struct regmap *regmap;
|
||||||
|
- struct mt7621_pci_phy_instance **phys;
|
||||||
|
- int nphys;
|
||||||
|
+ struct phy *phy;
|
||||||
|
+ void __iomem *port_base;
|
||||||
|
+ bool has_dual_port;
|
||||||
|
bool bypass_pipe_rst;
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -130,23 +120,23 @@ static inline void mt7621_phy_rmw(struct
|
||||||
|
phy_write(phy, val, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
-static void mt7621_bypass_pipe_rst(struct mt7621_pci_phy *phy,
|
||||||
|
- struct mt7621_pci_phy_instance *instance)
|
||||||
|
+static void mt7621_bypass_pipe_rst(struct mt7621_pci_phy *phy)
|
||||||
|
{
|
||||||
|
- u32 offset = (instance->index != 1) ?
|
||||||
|
- RG_PE1_PIPE_REG : RG_PE1_PIPE_REG + RG_P0_TO_P1_WIDTH;
|
||||||
|
+ mt7621_phy_rmw(phy, RG_PE1_PIPE_REG, 0, RG_PE1_PIPE_RST);
|
||||||
|
+ mt7621_phy_rmw(phy, RG_PE1_PIPE_REG, 0, RG_PE1_PIPE_CMD_FRC);
|
||||||
|
|
||||||
|
- mt7621_phy_rmw(phy, offset,
|
||||||
|
- RG_PE1_PIPE_RST | RG_PE1_PIPE_CMD_FRC,
|
||||||
|
- RG_PE1_PIPE_RST | RG_PE1_PIPE_CMD_FRC);
|
||||||
|
+ if (phy->has_dual_port) {
|
||||||
|
+ mt7621_phy_rmw(phy, RG_PE1_PIPE_REG + RG_P0_TO_P1_WIDTH,
|
||||||
|
+ 0, RG_PE1_PIPE_RST);
|
||||||
|
+ mt7621_phy_rmw(phy, RG_PE1_PIPE_REG + RG_P0_TO_P1_WIDTH,
|
||||||
|
+ 0, RG_PE1_PIPE_CMD_FRC);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
-static void mt7621_set_phy_for_ssc(struct mt7621_pci_phy *phy,
|
||||||
|
- struct mt7621_pci_phy_instance *instance)
|
||||||
|
+static void mt7621_set_phy_for_ssc(struct mt7621_pci_phy *phy)
|
||||||
|
{
|
||||||
|
struct device *dev = phy->dev;
|
||||||
|
u32 reg = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0);
|
||||||
|
- u32 offset;
|
||||||
|
|
||||||
|
reg = (reg >> 6) & 0x7;
|
||||||
|
/* Set PCIe Port PHY to disable SSC */
|
||||||
|
@@ -156,10 +146,13 @@ static void mt7621_set_phy_for_ssc(struc
|
||||||
|
RG_PE1_FRC_H_XTAL_TYPE | RG_PE1_H_XTAL_TYPE_VAL(0x00));
|
||||||
|
|
||||||
|
/* disable port */
|
||||||
|
- offset = (instance->index != 1) ?
|
||||||
|
- RG_PE1_FRC_PHY_REG : RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH;
|
||||||
|
- mt7621_phy_rmw(phy, offset,
|
||||||
|
- RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN);
|
||||||
|
+ mt7621_phy_rmw(phy, RG_PE1_FRC_PHY_REG,
|
||||||
|
+ RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN);
|
||||||
|
+
|
||||||
|
+ if (phy->has_dual_port) {
|
||||||
|
+ mt7621_phy_rmw(phy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH,
|
||||||
|
+ RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN);
|
||||||
|
+ }
|
||||||
|
|
||||||
|
if (reg <= 5 && reg >= 3) { /* 40MHz Xtal */
|
||||||
|
/* Set Pre-divider ratio (for host mode) */
|
||||||
|
@@ -223,43 +216,44 @@ static void mt7621_set_phy_for_ssc(struc
|
||||||
|
|
||||||
|
static int mt7621_pci_phy_init(struct phy *phy)
|
||||||
|
{
|
||||||
|
- struct mt7621_pci_phy_instance *instance = phy_get_drvdata(phy);
|
||||||
|
- struct mt7621_pci_phy *mphy = dev_get_drvdata(phy->dev.parent);
|
||||||
|
+ struct mt7621_pci_phy *mphy = phy_get_drvdata(phy);
|
||||||
|
|
||||||
|
if (mphy->bypass_pipe_rst)
|
||||||
|
- mt7621_bypass_pipe_rst(mphy, instance);
|
||||||
|
+ mt7621_bypass_pipe_rst(mphy);
|
||||||
|
|
||||||
|
- mt7621_set_phy_for_ssc(mphy, instance);
|
||||||
|
+ mt7621_set_phy_for_ssc(mphy);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mt7621_pci_phy_power_on(struct phy *phy)
|
||||||
|
{
|
||||||
|
- struct mt7621_pci_phy_instance *instance = phy_get_drvdata(phy);
|
||||||
|
- struct mt7621_pci_phy *mphy = dev_get_drvdata(phy->dev.parent);
|
||||||
|
- u32 offset = (instance->index != 1) ?
|
||||||
|
- RG_PE1_FRC_PHY_REG : RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH;
|
||||||
|
+ struct mt7621_pci_phy *mphy = phy_get_drvdata(phy);
|
||||||
|
|
||||||
|
/* Enable PHY and disable force mode */
|
||||||
|
- mt7621_phy_rmw(mphy, offset,
|
||||||
|
- RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN,
|
||||||
|
- RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN);
|
||||||
|
+ mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG,
|
||||||
|
+ RG_PE1_FRC_PHY_EN, RG_PE1_PHY_EN);
|
||||||
|
+
|
||||||
|
+ if (mphy->has_dual_port) {
|
||||||
|
+ mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH,
|
||||||
|
+ RG_PE1_FRC_PHY_EN, RG_PE1_PHY_EN);
|
||||||
|
+ }
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mt7621_pci_phy_power_off(struct phy *phy)
|
||||||
|
{
|
||||||
|
- struct mt7621_pci_phy_instance *instance = phy_get_drvdata(phy);
|
||||||
|
- struct mt7621_pci_phy *mphy = dev_get_drvdata(phy->dev.parent);
|
||||||
|
- u32 offset = (instance->index != 1) ?
|
||||||
|
- RG_PE1_FRC_PHY_REG : RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH;
|
||||||
|
+ struct mt7621_pci_phy *mphy = phy_get_drvdata(phy);
|
||||||
|
|
||||||
|
/* Disable PHY */
|
||||||
|
- mt7621_phy_rmw(mphy, offset,
|
||||||
|
- RG_PE1_FRC_PHY_EN | RG_PE1_PHY_EN,
|
||||||
|
- RG_PE1_FRC_PHY_EN);
|
||||||
|
+ mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG,
|
||||||
|
+ RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN);
|
||||||
|
+
|
||||||
|
+ if (mphy->has_dual_port) {
|
||||||
|
+ mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH,
|
||||||
|
+ RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN);
|
||||||
|
+ }
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@@ -282,13 +276,15 @@ static struct phy *mt7621_pcie_phy_of_xl
|
||||||
|
{
|
||||||
|
struct mt7621_pci_phy *mt7621_phy = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
- if (args->args_count == 0)
|
||||||
|
- return mt7621_phy->phys[0]->phy;
|
||||||
|
-
|
||||||
|
if (WARN_ON(args->args[0] >= MAX_PHYS))
|
||||||
|
return ERR_PTR(-ENODEV);
|
||||||
|
|
||||||
|
- return mt7621_phy->phys[args->args[0]]->phy;
|
||||||
|
+ mt7621_phy->has_dual_port = args->args[0];
|
||||||
|
+
|
||||||
|
+ dev_info(dev, "PHY for 0x%08x (dual port = %d)\n",
|
||||||
|
+ (unsigned int)mt7621_phy->port_base, mt7621_phy->has_dual_port);
|
||||||
|
+
|
||||||
|
+ return mt7621_phy->phy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct soc_device_attribute mt7621_pci_quirks_match[] = {
|
||||||
|
@@ -309,19 +305,11 @@ static int mt7621_pci_phy_probe(struct p
|
||||||
|
struct phy_provider *provider;
|
||||||
|
struct mt7621_pci_phy *phy;
|
||||||
|
struct resource *res;
|
||||||
|
- int port;
|
||||||
|
- void __iomem *port_base;
|
||||||
|
|
||||||
|
phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
|
||||||
|
if (!phy)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
- phy->nphys = MAX_PHYS;
|
||||||
|
- phy->phys = devm_kcalloc(dev, phy->nphys,
|
||||||
|
- sizeof(*phy->phys), GFP_KERNEL);
|
||||||
|
- if (!phy->phys)
|
||||||
|
- return -ENOMEM;
|
||||||
|
-
|
||||||
|
attr = soc_device_match(mt7621_pci_quirks_match);
|
||||||
|
if (attr)
|
||||||
|
phy->bypass_pipe_rst = true;
|
||||||
|
@@ -335,39 +323,25 @@ static int mt7621_pci_phy_probe(struct p
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- port_base = devm_ioremap_resource(dev, res);
|
||||||
|
- if (IS_ERR(port_base)) {
|
||||||
|
+ phy->port_base = devm_ioremap_resource(dev, res);
|
||||||
|
+ if (IS_ERR(phy->port_base)) {
|
||||||
|
dev_err(dev, "failed to remap phy regs\n");
|
||||||
|
- return PTR_ERR(port_base);
|
||||||
|
+ return PTR_ERR(phy->port_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
- phy->regmap = devm_regmap_init_mmio(phy->dev, port_base,
|
||||||
|
+ phy->regmap = devm_regmap_init_mmio(phy->dev, phy->port_base,
|
||||||
|
&mt7621_pci_phy_regmap_config);
|
||||||
|
if (IS_ERR(phy->regmap))
|
||||||
|
return PTR_ERR(phy->regmap);
|
||||||
|
|
||||||
|
- for (port = 0; port < MAX_PHYS; port++) {
|
||||||
|
- struct mt7621_pci_phy_instance *instance;
|
||||||
|
- struct phy *pphy;
|
||||||
|
-
|
||||||
|
- instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL);
|
||||||
|
- if (!instance)
|
||||||
|
- return -ENOMEM;
|
||||||
|
-
|
||||||
|
- phy->phys[port] = instance;
|
||||||
|
-
|
||||||
|
- pphy = devm_phy_create(dev, dev->of_node, &mt7621_pci_phy_ops);
|
||||||
|
- if (IS_ERR(phy)) {
|
||||||
|
- dev_err(dev, "failed to create phy\n");
|
||||||
|
- return PTR_ERR(phy);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- instance->port_base = port_base;
|
||||||
|
- instance->phy = pphy;
|
||||||
|
- instance->index = port;
|
||||||
|
- phy_set_drvdata(pphy, instance);
|
||||||
|
+ phy->phy = devm_phy_create(dev, dev->of_node, &mt7621_pci_phy_ops);
|
||||||
|
+ if (IS_ERR(phy)) {
|
||||||
|
+ dev_err(dev, "failed to create phy\n");
|
||||||
|
+ return PTR_ERR(phy);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ phy_set_drvdata(phy->phy, phy);
|
||||||
|
+
|
||||||
|
provider = devm_of_phy_provider_register(dev, mt7621_pcie_phy_of_xlate);
|
||||||
|
|
||||||
|
return PTR_ERR_OR_ZERO(provider);
|
@ -0,0 +1,42 @@
|
|||||||
|
From c752b54bda4d772426c5eeb56978d2e41bd525b4 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Fri, 20 Mar 2020 12:01:21 +0100
|
||||||
|
Subject: [PATCH] staging: mt7621-pci: use only two phys from device tree
|
||||||
|
|
||||||
|
In order to align work with the mt7621-pci-phy part of
|
||||||
|
the driver and device tree which is now using only two
|
||||||
|
real phys one of them dual ported properly parse the
|
||||||
|
device tree and don't call phy initialization for the
|
||||||
|
slot 1 because is being taking into account when the
|
||||||
|
phy for the slot 0 is instantiated.
|
||||||
|
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20200320110123.9907-4-sergio.paracuellos@gmail.com
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
---
|
||||||
|
drivers/staging/mt7621-pci/pci-mt7621.c | 7 ++++++-
|
||||||
|
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
@@ -358,7 +358,7 @@ static int mt7621_pcie_parse_port(struct
|
||||||
|
|
||||||
|
snprintf(name, sizeof(name), "pcie-phy%d", slot);
|
||||||
|
port->phy = devm_phy_get(dev, name);
|
||||||
|
- if (IS_ERR(port->phy))
|
||||||
|
+ if (IS_ERR(port->phy) && slot != 1)
|
||||||
|
return PTR_ERR(port->phy);
|
||||||
|
|
||||||
|
port->gpio_rst = devm_gpiod_get_index_optional(dev, "reset", slot,
|
||||||
|
@@ -495,6 +495,11 @@ static void mt7621_pcie_init_ports(struc
|
||||||
|
list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
|
||||||
|
u32 slot = port->slot;
|
||||||
|
|
||||||
|
+ if (slot == 1) {
|
||||||
|
+ port->enabled = true;
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
err = mt7621_pcie_init_port(port);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "Initiating port %d failed\n", slot);
|
@ -0,0 +1,26 @@
|
|||||||
|
From b59343b7de448c30e5b098484a7c7c5cb300df2f Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Fri, 20 Mar 2020 12:01:22 +0100
|
||||||
|
Subject: [PATCH] staging: mt7621-pci: change variable to print for slot
|
||||||
|
|
||||||
|
We are using the counter to print the slot which has been
|
||||||
|
enabled. Use the correct associated slot for the port instead.
|
||||||
|
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20200320110123.9907-5-sergio.paracuellos@gmail.com
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
---
|
||||||
|
drivers/staging/mt7621-pci/pci-mt7621.c | 2 +-
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
@@ -562,7 +562,7 @@ static void mt7621_pcie_enable_ports(str
|
||||||
|
if (port->enabled) {
|
||||||
|
mt7621_pcie_port_clk_enable(port);
|
||||||
|
mt7621_pcie_enable_port(port);
|
||||||
|
- dev_info(dev, "PCIE%d enabled\n", num_slots_enabled);
|
||||||
|
+ dev_info(dev, "PCIE%d enabled\n", port->slot);
|
||||||
|
num_slots_enabled++;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
From 87068309300c707d659ce79232eae827604804a4 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Fri, 20 Mar 2020 12:01:23 +0100
|
||||||
|
Subject: [PATCH] staging: mt7621-pci: be sure gpio descriptor is null on fails
|
||||||
|
|
||||||
|
Function 'devm_gpiod_get_index_optional' returns NULL if the
|
||||||
|
descriptor is invalid and the error associated for the error
|
||||||
|
pointer is ENOENT. Sometimes if the pin is just assigned the
|
||||||
|
error associated for the pointer might not be ENOENT but other.
|
||||||
|
In order to avoid weirds behaviours if this happen set descriptor
|
||||||
|
to NULL in the driver port structure.
|
||||||
|
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20200320110123.9907-6-sergio.paracuellos@gmail.com
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
---
|
||||||
|
drivers/staging/mt7621-pci/pci-mt7621.c | 4 +++-
|
||||||
|
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
@@ -363,8 +363,10 @@ static int mt7621_pcie_parse_port(struct
|
||||||
|
|
||||||
|
port->gpio_rst = devm_gpiod_get_index_optional(dev, "reset", slot,
|
||||||
|
GPIOD_OUT_LOW);
|
||||||
|
- if (IS_ERR(port->gpio_rst))
|
||||||
|
+ if (IS_ERR(port->gpio_rst)) {
|
||||||
|
dev_notice(dev, "Failed to get GPIO for PCIe%d\n", slot);
|
||||||
|
+ port->gpio_rst = NULL;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
port->slot = slot;
|
||||||
|
port->pcie = pcie;
|
@ -0,0 +1,79 @@
|
|||||||
|
From d81fe3c13aa6f4ab1ec318212d2007175e6d05aa Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Fri, 20 Mar 2020 16:38:37 +0100
|
||||||
|
Subject: [PATCH] staging: mt7621-pci: avoid to poweroff the phy for slot one
|
||||||
|
|
||||||
|
Phy for slot 0 and 1 is shared and handled properly in slot 0.
|
||||||
|
If there is only one port in use,(slot 0) we shall not call the
|
||||||
|
'phy_power_off' function with an invalid slot because kernel
|
||||||
|
will crash with an unaligned access fault like the following:
|
||||||
|
|
||||||
|
mt7621-pci 1e140000.pcie: Error applying setting, reverse things back
|
||||||
|
mt7621-pci-phy 1e149000.pcie-phy: PHY for 0xbe149000 (dual port = 1)
|
||||||
|
mt7621-pci-phy 1e14a000.pcie-phy: PHY for 0xbe14a000 (dual port = 0)
|
||||||
|
mt7621-pci-phy 1e149000.pcie-phy: Xtal is 40MHz
|
||||||
|
mt7621-pci-phy 1e14a000.pcie-phy: Xtal is 40MHz
|
||||||
|
mt7621-pci 1e140000.pcie: pcie1 no card, disable it (RST & CLK)
|
||||||
|
Unhandled kernel unaligned access[#1]:
|
||||||
|
CPU: 3 PID: 111 Comm: kworker/3:2 Not tainted 5.6.0-rc3-00347-g825c6f470c62-dirty #9
|
||||||
|
Workqueue: events deferred_probe_work_func
|
||||||
|
$ 0 : 00000000 00000001 5f60d043 8fe1ba80
|
||||||
|
$ 4 : 0000010d 01eb9000 00000000 00000000
|
||||||
|
$ 8 : 294b4c00 80940000 00000008 000000ce
|
||||||
|
$12 : 2e303030 00000000 00000000 65696370
|
||||||
|
$16 : ffffffed 0000010d 8e373cd0 8214c1e0
|
||||||
|
$20 : 00000000 82144c80 82144680 8214c250
|
||||||
|
$24 : 00000018 803ef8f4
|
||||||
|
$28 : 8e372000 8e373c60 8214c080 803940e8
|
||||||
|
Hi : 00000125
|
||||||
|
Lo : 122f2000
|
||||||
|
epc : 807b3328 mutex_lock+0x8/0x44
|
||||||
|
ra : 803940e8 phy_power_off+0x28/0xb0
|
||||||
|
Status: 1100fc03 KERNEL EXL IE
|
||||||
|
Cause : 00800010 (ExcCode 04)
|
||||||
|
BadVA : 0000010d
|
||||||
|
PrId : 0001992f (MIPS 1004Kc)
|
||||||
|
Modules linked in:
|
||||||
|
Process kworker/3:2 (pid: 111, threadinfo=(ptrval), task=(ptrval), tls=00000000)
|
||||||
|
Stack : 8e373cd0 803fe4f4 8e372000 8e373c90 8214c080 804fde1c 8e373c98 808d62f4
|
||||||
|
8e373c78 00000000 8214c254 804fe648 1e160000 804f27b8 00000001 808d62f4
|
||||||
|
00000000 00000001 8214c228 808d62f4 80930000 809a0000 8fd47e10 808d63d4
|
||||||
|
808d62d4 8fd47e10 808d0000 808d0000 8e373cd0 8e373cd0 809e2a74 809db510
|
||||||
|
809db510 00000006 00000001 00000000 00000000 00000000 01000000 1e1440ff
|
||||||
|
...
|
||||||
|
Call Trace:
|
||||||
|
[<807b3328>] mutex_lock+0x8/0x44
|
||||||
|
[<803940e8>] phy_power_off+0x28/0xb0
|
||||||
|
[<804fe648>] mt7621_pci_probe+0xc20/0xd18
|
||||||
|
[<80402ab8>] platform_drv_probe+0x40/0x94
|
||||||
|
[<80400a74>] really_probe+0x104/0x364
|
||||||
|
[<803feb74>] bus_for_each_drv+0x84/0xdc
|
||||||
|
[<80400924>] __device_attach+0xdc/0x120
|
||||||
|
[<803ffb5c>] bus_probe_device+0xa0/0xbc
|
||||||
|
[<80400124>] deferred_probe_work_func+0x7c/0xbc
|
||||||
|
[<800420e8>] process_one_work+0x230/0x450
|
||||||
|
[<80042638>] worker_thread+0x330/0x5fc
|
||||||
|
[<80048eb0>] kthread+0x12c/0x134
|
||||||
|
[<80007438>] ret_from_kernel_thread+0x14/0x1c
|
||||||
|
Code: 24050002 27bdfff8 8f830000 <c0850000> 14a00005 00000000 00600825 e0810000 1020fffa
|
||||||
|
|
||||||
|
Fixes: bf516f413f4e ("staging: mt7621-pci: use only two phys from device tree")
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20200320153837.20415-1-sergio.paracuellos@gmail.com
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
---
|
||||||
|
drivers/staging/mt7621-pci/pci-mt7621.c | 3 ++-
|
||||||
|
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
@@ -517,7 +517,8 @@ static void mt7621_pcie_init_ports(struc
|
||||||
|
if (!mt7621_pcie_port_is_linkup(port)) {
|
||||||
|
dev_err(dev, "pcie%d no card, disable it (RST & CLK)\n",
|
||||||
|
slot);
|
||||||
|
- phy_power_off(port->phy);
|
||||||
|
+ if (slot != 1)
|
||||||
|
+ phy_power_off(port->phy);
|
||||||
|
mt7621_control_assert(port);
|
||||||
|
mt7621_pcie_port_clk_disable(port);
|
||||||
|
port->enabled = false;
|
@ -0,0 +1,91 @@
|
|||||||
|
From 9d789a7728c37e8730b6a9cca60cf155f18537ea Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Sat, 21 Mar 2020 08:26:50 +0100
|
||||||
|
Subject: [PATCH] staging: mt7621-pci: delete release gpios related code
|
||||||
|
|
||||||
|
Making gpio8 and gpio9 vendor specific and putting them
|
||||||
|
into the specific dts file makes not needed to release
|
||||||
|
gpios anymore because we are not occupying those pins
|
||||||
|
in the first place if it is not necessary. When the
|
||||||
|
device tree is parsed we can also check and return for
|
||||||
|
the error because we rely in the fact that the related
|
||||||
|
device for the board is correct.
|
||||||
|
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20200321072650.7784-3-sergio.paracuellos@gmail.com
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
---
|
||||||
|
drivers/staging/mt7621-pci/pci-mt7621.c | 27 +++++++--------------------
|
||||||
|
1 file changed, 7 insertions(+), 20 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
@@ -364,8 +364,8 @@ static int mt7621_pcie_parse_port(struct
|
||||||
|
port->gpio_rst = devm_gpiod_get_index_optional(dev, "reset", slot,
|
||||||
|
GPIOD_OUT_LOW);
|
||||||
|
if (IS_ERR(port->gpio_rst)) {
|
||||||
|
- dev_notice(dev, "Failed to get GPIO for PCIe%d\n", slot);
|
||||||
|
- port->gpio_rst = NULL;
|
||||||
|
+ dev_err(dev, "Failed to get GPIO for PCIe%d\n", slot);
|
||||||
|
+ return PTR_ERR(port->gpio_rst);
|
||||||
|
}
|
||||||
|
|
||||||
|
port->slot = slot;
|
||||||
|
@@ -474,15 +474,6 @@ static void mt7621_pcie_reset_ep_deasser
|
||||||
|
mdelay(PERST_DELAY_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
-static void mt7621_pcie_release_gpios(struct mt7621_pcie *pcie)
|
||||||
|
-{
|
||||||
|
- struct mt7621_pcie_port *port;
|
||||||
|
-
|
||||||
|
- list_for_each_entry(port, &pcie->ports, list)
|
||||||
|
- if (port->gpio_rst)
|
||||||
|
- gpiod_put(port->gpio_rst);
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
|
||||||
|
{
|
||||||
|
struct device *dev = pcie->dev;
|
||||||
|
@@ -684,7 +675,7 @@ static int mt7621_pci_probe(struct platf
|
||||||
|
err = mt7621_pci_parse_request_of_pci_ranges(pcie);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "Error requesting pci resources from ranges");
|
||||||
|
- goto out_release_gpios;
|
||||||
|
+ return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set resources limits */
|
||||||
|
@@ -698,8 +689,7 @@ static int mt7621_pci_probe(struct platf
|
||||||
|
err = mt7621_pcie_init_virtual_bridges(pcie);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "Nothing is connected in virtual bridges. Exiting...");
|
||||||
|
- err = 0;
|
||||||
|
- goto out_release_gpios;
|
||||||
|
+ return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mt7621_pcie_enable_ports(pcie);
|
||||||
|
@@ -709,19 +699,16 @@ static int mt7621_pci_probe(struct platf
|
||||||
|
err = mt7621_pcie_request_resources(pcie, &res);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "Error requesting resources\n");
|
||||||
|
- goto out_release_gpios;
|
||||||
|
+ return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = mt7621_pcie_register_host(bridge, &res);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "Error registering host\n");
|
||||||
|
- goto out_release_gpios;
|
||||||
|
+ return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
-out_release_gpios:
|
||||||
|
- mt7621_pcie_release_gpios(pcie);
|
||||||
|
-
|
||||||
|
- return err;
|
||||||
|
+ return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id mt7621_pci_ids[] = {
|
@ -0,0 +1,29 @@
|
|||||||
|
From 60a15339ceab9fc2a6cdc85fd54b66b2c947ab4e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Sat, 21 Mar 2020 14:36:21 +0100
|
||||||
|
Subject: [PATCH] staging: mt7621-pci: use builtin_platform_driver()
|
||||||
|
|
||||||
|
Macro builtin_platform_driver can be used for builtin drivers
|
||||||
|
that don't do anything in driver init. So, use the macro
|
||||||
|
builtin_platform_driver and remove some boilerplate code.
|
||||||
|
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20200321133624.31388-1-sergio.paracuellos@gmail.com
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
---
|
||||||
|
drivers/staging/mt7621-pci/pci-mt7621.c | 7 +------
|
||||||
|
1 file changed, 1 insertion(+), 6 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
@@ -725,9 +725,4 @@ static struct platform_driver mt7621_pci
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
-static int __init mt7621_pci_init(void)
|
||||||
|
-{
|
||||||
|
- return platform_driver_register(&mt7621_pci_driver);
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-module_init(mt7621_pci_init);
|
||||||
|
+builtin_platform_driver(mt7621_pci_driver);
|
@ -0,0 +1,32 @@
|
|||||||
|
From ffe3dee4081055b4f58bc50dd3f5c97de42cf126 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Sat, 21 Mar 2020 14:36:23 +0100
|
||||||
|
Subject: [PATCH] staging: mt7621-pci-phy: use builtin_platform_driver()
|
||||||
|
|
||||||
|
Macro builtin_platform_driver can be used for builtin drivers
|
||||||
|
that don't do anything in driver init. So, use the macro
|
||||||
|
builtin_platform_driver and remove some boilerplate code.
|
||||||
|
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20200321133624.31388-3-sergio.paracuellos@gmail.com
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
---
|
||||||
|
drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c | 7 +------
|
||||||
|
1 file changed, 1 insertion(+), 6 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c
|
||||||
|
+++ b/drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c
|
||||||
|
@@ -361,12 +361,7 @@ static struct platform_driver mt7621_pci
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
-static int __init mt7621_pci_phy_drv_init(void)
|
||||||
|
-{
|
||||||
|
- return platform_driver_register(&mt7621_pci_phy_driver);
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-module_init(mt7621_pci_phy_drv_init);
|
||||||
|
+builtin_platform_driver(mt7621_pci_phy_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Sergio Paracuellos <sergio.paracuellos@gmail.com>");
|
||||||
|
MODULE_DESCRIPTION("MediaTek MT7621 PCIe PHY driver");
|
@ -0,0 +1,68 @@
|
|||||||
|
From ff83e3023cb8fc3b5dfc12e0c91bf1eb9dc4c4c6 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Sat, 21 Mar 2020 14:36:24 +0100
|
||||||
|
Subject: [PATCH] staging: mt7621-pci-phy: re-do 'xtal_mode' detection
|
||||||
|
|
||||||
|
Detection of the Xtal mode is using magic numbers that
|
||||||
|
can be avoided using properly some definitions and a more
|
||||||
|
accurate variable name from 'reg' into 'xtal_mode'. This
|
||||||
|
increase readability.
|
||||||
|
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20200321133624.31388-4-sergio.paracuellos@gmail.com
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
---
|
||||||
|
drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c | 15 ++++++++++-----
|
||||||
|
1 file changed, 10 insertions(+), 5 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c
|
||||||
|
+++ b/drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c
|
||||||
|
@@ -75,6 +75,9 @@
|
||||||
|
|
||||||
|
#define RG_PE1_FRC_MSTCKDIV BIT(5)
|
||||||
|
|
||||||
|
+#define XTAL_MODE_SEL_SHIFT 6
|
||||||
|
+#define XTAL_MODE_SEL_MASK 0x7
|
||||||
|
+
|
||||||
|
#define MAX_PHYS 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -136,9 +139,11 @@ static void mt7621_bypass_pipe_rst(struc
|
||||||
|
static void mt7621_set_phy_for_ssc(struct mt7621_pci_phy *phy)
|
||||||
|
{
|
||||||
|
struct device *dev = phy->dev;
|
||||||
|
- u32 reg = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0);
|
||||||
|
+ u32 xtal_mode;
|
||||||
|
+
|
||||||
|
+ xtal_mode = (rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0)
|
||||||
|
+ >> XTAL_MODE_SEL_SHIFT) & XTAL_MODE_SEL_MASK;
|
||||||
|
|
||||||
|
- reg = (reg >> 6) & 0x7;
|
||||||
|
/* Set PCIe Port PHY to disable SSC */
|
||||||
|
/* Debug Xtal Type */
|
||||||
|
mt7621_phy_rmw(phy, RG_PE1_FRC_H_XTAL_REG,
|
||||||
|
@@ -154,13 +159,13 @@ static void mt7621_set_phy_for_ssc(struc
|
||||||
|
RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN);
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (reg <= 5 && reg >= 3) { /* 40MHz Xtal */
|
||||||
|
+ if (xtal_mode <= 5 && xtal_mode >= 3) { /* 40MHz Xtal */
|
||||||
|
/* Set Pre-divider ratio (for host mode) */
|
||||||
|
mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG,
|
||||||
|
RG_PE1_H_PLL_PREDIV,
|
||||||
|
RG_PE1_H_PLL_PREDIV_VAL(0x01));
|
||||||
|
dev_info(dev, "Xtal is 40MHz\n");
|
||||||
|
- } else if (reg >= 6) { /* 25MHz Xal */
|
||||||
|
+ } else if (xtal_mode >= 6) { /* 25MHz Xal */
|
||||||
|
mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG,
|
||||||
|
RG_PE1_H_PLL_PREDIV,
|
||||||
|
RG_PE1_H_PLL_PREDIV_VAL(0x00));
|
||||||
|
@@ -206,7 +211,7 @@ static void mt7621_set_phy_for_ssc(struc
|
||||||
|
mt7621_phy_rmw(phy, RG_PE1_H_PLL_BR_REG,
|
||||||
|
RG_PE1_H_PLL_BR, RG_PE1_H_PLL_BR_VAL(0x00));
|
||||||
|
|
||||||
|
- if (reg <= 5 && reg >= 3) { /* 40MHz Xtal */
|
||||||
|
+ if (xtal_mode <= 5 && xtal_mode >= 3) { /* 40MHz Xtal */
|
||||||
|
/* set force mode enable of da_pe1_mstckdiv */
|
||||||
|
mt7621_phy_rmw(phy, RG_PE1_MSTCKDIV_REG,
|
||||||
|
RG_PE1_MSTCKDIV | RG_PE1_FRC_MSTCKDIV,
|
@ -0,0 +1,35 @@
|
|||||||
|
From 4f0f36b67564311a4ce4441510ef94848febbab2 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Sun, 22 Mar 2020 08:21:28 +0100
|
||||||
|
Subject: [PATCH] staging: mt7621-pci: avoid to set 'iomem_resource' addresses
|
||||||
|
|
||||||
|
Setting up kernel resource 'iomem_resource' for PCI with
|
||||||
|
addresses parsed from device tree gots into a conflict within
|
||||||
|
the usb xhci driver:
|
||||||
|
|
||||||
|
xhci-mtk 1e1c0000.xhci: can't request region for resource [mem 0x1e1c0000-0x1e1c0fff]
|
||||||
|
xhci-mtk: probe of 1e1c0000.xhci failed with error -16
|
||||||
|
|
||||||
|
Don't assign it and maintain the default addresses for this
|
||||||
|
resource seems to fix the problem. Checking legacy driver it
|
||||||
|
is being only setting the 'ioport_resource'.
|
||||||
|
|
||||||
|
Fixes: 09dd629eeabb ("staging: mt7621-pci: fix io space and properly set resource limits")
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20200322072128.4454-1-sergio.paracuellos@gmail.com
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
---
|
||||||
|
drivers/staging/mt7621-pci/pci-mt7621.c | 2 --
|
||||||
|
1 file changed, 2 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
@@ -679,8 +679,6 @@ static int mt7621_pci_probe(struct platf
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set resources limits */
|
||||||
|
- iomem_resource.start = pcie->mem.start;
|
||||||
|
- iomem_resource.end = pcie->mem.end;
|
||||||
|
ioport_resource.start = pcie->io.start;
|
||||||
|
ioport_resource.end = pcie->io.end;
|
||||||
|
|
@ -0,0 +1,65 @@
|
|||||||
|
From 5fcded5e857cf66c9592e4be28c4dab4520c9177 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Thu, 9 Apr 2020 13:16:52 +0200
|
||||||
|
Subject: [PATCH] staging: mt7621-pci: properly power off dual-ported pcie phy
|
||||||
|
|
||||||
|
Pcie phy for pcie0 and pcie1 is shared using a dual ported
|
||||||
|
one. Current code was assuming that if nothing is connected
|
||||||
|
in pcie0 it won't be also nothing connected in pcie1. This
|
||||||
|
assumtion is wrong for some devices such us 'Mikrotik rbm33g'
|
||||||
|
and 'ZyXEL LTE3301-PLUS' where only connecting a card to the
|
||||||
|
second bus on the phy is possible. For such devices kernel
|
||||||
|
hangs in the same point because of the wrong poweroff of the
|
||||||
|
phy getting the following trace:
|
||||||
|
|
||||||
|
mt7621-pci-phy 1e149000.pcie-phy: PHY for 0xbe149000 (dual port = 1)
|
||||||
|
mt7621-pci-phy 1e14a000.pcie-phy: PHY for 0xbe14a000 (dual port = 0)
|
||||||
|
mt7621-pci-phy 1e149000.pcie-phy: Xtal is 40MHz
|
||||||
|
mt7621-pci-phy 1e14a000.pcie-phy: Xtal is 40MHz
|
||||||
|
mt7621-pci 1e140000.pcie: pcie0 no card, disable it (RST & CLK)
|
||||||
|
[hangs]
|
||||||
|
|
||||||
|
The wrong assumption is located in the 'mt7621_pcie_init_ports'
|
||||||
|
function where we are just making a power off of the phy for
|
||||||
|
slots 0 and 2 if nothing is connected in them. Hence, only
|
||||||
|
poweroff the phy if nothing is connected in both slot 0 and
|
||||||
|
slot 1 avoiding the kernel to hang.
|
||||||
|
|
||||||
|
Fixes: 5737cfe87a9c ("staging: mt7621-pci: avoid to poweroff the phy for slot one")
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20200409111652.30964-1-sergio.paracuellos@gmail.com
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
---
|
||||||
|
drivers/staging/mt7621-pci/pci-mt7621.c | 12 ++++++++++--
|
||||||
|
1 file changed, 10 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
@@ -502,17 +502,25 @@ static void mt7621_pcie_init_ports(struc
|
||||||
|
|
||||||
|
mt7621_pcie_reset_ep_deassert(pcie);
|
||||||
|
|
||||||
|
+ tmp = NULL;
|
||||||
|
list_for_each_entry(port, &pcie->ports, list) {
|
||||||
|
u32 slot = port->slot;
|
||||||
|
|
||||||
|
if (!mt7621_pcie_port_is_linkup(port)) {
|
||||||
|
dev_err(dev, "pcie%d no card, disable it (RST & CLK)\n",
|
||||||
|
slot);
|
||||||
|
- if (slot != 1)
|
||||||
|
- phy_power_off(port->phy);
|
||||||
|
mt7621_control_assert(port);
|
||||||
|
mt7621_pcie_port_clk_disable(port);
|
||||||
|
port->enabled = false;
|
||||||
|
+
|
||||||
|
+ if (slot == 0) {
|
||||||
|
+ tmp = port;
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (slot == 1 && tmp && !tmp->enabled)
|
||||||
|
+ phy_power_off(tmp->phy);
|
||||||
|
+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,157 @@
|
|||||||
|
From fab6710e4c51f4eb622f95a08322ab5fdbe3f295 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Mon, 13 Apr 2020 07:59:42 +0200
|
||||||
|
Subject: [PATCH] staging: mt7621-pci: fix PCIe interrupt mapping
|
||||||
|
|
||||||
|
MT7621 has three assigned interrupts for the pcie. This
|
||||||
|
interrupts should properly being mapped taking into account
|
||||||
|
which devices are finally connected in which bus according
|
||||||
|
to link status. So the irq mappings should be as follows
|
||||||
|
according to link status (three bits indicating which devices
|
||||||
|
are link up):
|
||||||
|
|
||||||
|
* For PCIe Bus 1 slot 0:
|
||||||
|
- status = 0x2 || status = 0x6 => IRQ = pcie1_irq (24).
|
||||||
|
- status = 0x4 => IRQ = pcie2_irq (25).
|
||||||
|
- default => IRQ = pcie0_irq (23).
|
||||||
|
* For PCIe Bus 2 slot 0:
|
||||||
|
- status = 0x5 || status = 0x6 => IRQ = pcie2_irq (25).
|
||||||
|
- default => IRQ = pcie1_irq (24).
|
||||||
|
* For PCIe Bus 2 slot 1:
|
||||||
|
- status = 0x5 || status = 0x6 => IRQ = pcie2_irq (25).
|
||||||
|
- default => IRQ = pcie1_irq (24).
|
||||||
|
* For PCIe Bus 3 any slot:
|
||||||
|
- default => IRQ = pcie2_irq (25).
|
||||||
|
|
||||||
|
Because of this, the function 'of_irq_parse_and_map_pci' cannot
|
||||||
|
be used and we need to change device tree information from using
|
||||||
|
the 'interrupt-map' and 'interrupt-map-mask' properties into an
|
||||||
|
'interrupts' property to be able to get irq information from the
|
||||||
|
ports using the 'platform_get_irq' and storing an 'irq-map' into
|
||||||
|
the pcie driver data node to properly map correct irq using a
|
||||||
|
new 'mt7621_map_irq' function where this map will be read and the
|
||||||
|
correct irq returned.
|
||||||
|
|
||||||
|
Fixes: 46d093124df4 ("staging: mt7621-pci: improve interrupt mapping")
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Link: https://lore.kernel.org/r/20200413055942.2714-1-sergio.paracuellos@gmail.com
|
||||||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
---
|
||||||
|
drivers/staging/mt7621-dts/mt7621.dtsi | 9 +++----
|
||||||
|
drivers/staging/mt7621-pci/pci-mt7621.c | 36 +++++++++++++++++++++++--
|
||||||
|
2 files changed, 38 insertions(+), 7 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
|
||||||
|
@@ -97,6 +97,7 @@
|
||||||
|
* @pcie_rst: pointer to port reset control
|
||||||
|
* @gpio_rst: gpio reset
|
||||||
|
* @slot: port slot
|
||||||
|
+ * @irq: GIC irq
|
||||||
|
* @enabled: indicates if port is enabled
|
||||||
|
*/
|
||||||
|
struct mt7621_pcie_port {
|
||||||
|
@@ -107,6 +108,7 @@ struct mt7621_pcie_port {
|
||||||
|
struct reset_control *pcie_rst;
|
||||||
|
struct gpio_desc *gpio_rst;
|
||||||
|
u32 slot;
|
||||||
|
+ int irq;
|
||||||
|
bool enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -120,6 +122,7 @@ struct mt7621_pcie_port {
|
||||||
|
* @dev: Pointer to PCIe device
|
||||||
|
* @io_map_base: virtual memory base address for io
|
||||||
|
* @ports: pointer to PCIe port information
|
||||||
|
+ * @irq_map: irq mapping info according pcie link status
|
||||||
|
* @resets_inverted: depends on chip revision
|
||||||
|
* reset lines are inverted.
|
||||||
|
*/
|
||||||
|
@@ -135,6 +138,7 @@ struct mt7621_pcie {
|
||||||
|
} offset;
|
||||||
|
unsigned long io_map_base;
|
||||||
|
struct list_head ports;
|
||||||
|
+ int irq_map[PCIE_P2P_MAX];
|
||||||
|
bool resets_inverted;
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -279,6 +283,16 @@ static void setup_cm_memory_region(struc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int mt7621_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
|
||||||
|
+{
|
||||||
|
+ struct mt7621_pcie *pcie = pdev->bus->sysdata;
|
||||||
|
+ struct device *dev = pcie->dev;
|
||||||
|
+ int irq = pcie->irq_map[slot];
|
||||||
|
+
|
||||||
|
+ dev_info(dev, "bus=%d slot=%d irq=%d\n", pdev->bus->number, slot, irq);
|
||||||
|
+ return irq;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int mt7621_pci_parse_request_of_pci_ranges(struct mt7621_pcie *pcie)
|
||||||
|
{
|
||||||
|
struct device *dev = pcie->dev;
|
||||||
|
@@ -330,6 +344,7 @@ static int mt7621_pcie_parse_port(struct
|
||||||
|
{
|
||||||
|
struct mt7621_pcie_port *port;
|
||||||
|
struct device *dev = pcie->dev;
|
||||||
|
+ struct platform_device *pdev = to_platform_device(dev);
|
||||||
|
struct device_node *pnode = dev->of_node;
|
||||||
|
struct resource regs;
|
||||||
|
char name[10];
|
||||||
|
@@ -371,6 +386,12 @@ static int mt7621_pcie_parse_port(struct
|
||||||
|
port->slot = slot;
|
||||||
|
port->pcie = pcie;
|
||||||
|
|
||||||
|
+ port->irq = platform_get_irq(pdev, slot);
|
||||||
|
+ if (port->irq < 0) {
|
||||||
|
+ dev_err(dev, "Failed to get IRQ for PCIe%d\n", slot);
|
||||||
|
+ return -ENXIO;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
INIT_LIST_HEAD(&port->list);
|
||||||
|
list_add_tail(&port->list, &pcie->ports);
|
||||||
|
|
||||||
|
@@ -585,13 +606,15 @@ static int mt7621_pcie_init_virtual_brid
|
||||||
|
{
|
||||||
|
u32 pcie_link_status = 0;
|
||||||
|
u32 n;
|
||||||
|
- int i;
|
||||||
|
+ int i = 0;
|
||||||
|
u32 p2p_br_devnum[PCIE_P2P_MAX];
|
||||||
|
+ int irqs[PCIE_P2P_MAX];
|
||||||
|
struct mt7621_pcie_port *port;
|
||||||
|
|
||||||
|
list_for_each_entry(port, &pcie->ports, list) {
|
||||||
|
u32 slot = port->slot;
|
||||||
|
|
||||||
|
+ irqs[i++] = port->irq;
|
||||||
|
if (port->enabled)
|
||||||
|
pcie_link_status |= BIT(slot);
|
||||||
|
}
|
||||||
|
@@ -614,6 +637,15 @@ static int mt7621_pcie_init_virtual_brid
|
||||||
|
(p2p_br_devnum[1] << PCIE_P2P_BR_DEVNUM1_SHIFT) |
|
||||||
|
(p2p_br_devnum[2] << PCIE_P2P_BR_DEVNUM2_SHIFT));
|
||||||
|
|
||||||
|
+ /* Assign IRQs */
|
||||||
|
+ n = 0;
|
||||||
|
+ for (i = 0; i < PCIE_P2P_MAX; i++)
|
||||||
|
+ if (pcie_link_status & BIT(i))
|
||||||
|
+ pcie->irq_map[n++] = irqs[i];
|
||||||
|
+
|
||||||
|
+ for (i = n; i < PCIE_P2P_MAX; i++)
|
||||||
|
+ pcie->irq_map[i] = -1;
|
||||||
|
+
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -638,7 +670,7 @@ static int mt7621_pcie_register_host(str
|
||||||
|
host->busnr = pcie->busn.start;
|
||||||
|
host->dev.parent = pcie->dev;
|
||||||
|
host->ops = &mt7621_pci_ops;
|
||||||
|
- host->map_irq = of_irq_parse_and_map_pci;
|
||||||
|
+ host->map_irq = mt7621_map_irq;
|
||||||
|
host->swizzle_irq = pci_common_swizzle;
|
||||||
|
host->sysdata = pcie;
|
||||||
|
|
@ -0,0 +1,26 @@
|
|||||||
|
From 1f0400d0e2c410b04f246aefb2e9b5155eb4b0bf Mon Sep 17 00:00:00 2001
|
||||||
|
From: Chuanhong Guo <gch981213@gmail.com>
|
||||||
|
Date: Tue, 13 Oct 2020 10:05:47 +0800
|
||||||
|
Subject: mips: ralink: enable zboot support
|
||||||
|
|
||||||
|
Some of these ralink devices come with an ancient u-boot which can't
|
||||||
|
extract LZMA properly when image gets too big.
|
||||||
|
Enable zboot support to get a self-extracting kernel instead of relying
|
||||||
|
on broken u-boot support.
|
||||||
|
|
||||||
|
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
|
||||||
|
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
|
||||||
|
---
|
||||||
|
arch/mips/Kconfig | 1 +
|
||||||
|
1 file changed, 1 insertion(+)
|
||||||
|
|
||||||
|
--- a/arch/mips/Kconfig
|
||||||
|
+++ b/arch/mips/Kconfig
|
||||||
|
@@ -625,6 +625,7 @@ config RALINK
|
||||||
|
select SYS_SUPPORTS_32BIT_KERNEL
|
||||||
|
select SYS_SUPPORTS_LITTLE_ENDIAN
|
||||||
|
select SYS_SUPPORTS_MIPS16
|
||||||
|
+ select SYS_SUPPORTS_ZBOOT
|
||||||
|
select SYS_HAS_EARLY_PRINTK
|
||||||
|
select CLKDEV_LOOKUP
|
||||||
|
select ARCH_HAS_RESET_CONTROLLER
|
@ -0,0 +1,45 @@
|
|||||||
|
From 3f9ef7785a9cd69cb75f5e2ea4ca79a24752e496 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sander Vanheule <sander@svanheule.net>
|
||||||
|
Date: Wed, 3 Feb 2021 10:21:41 +0100
|
||||||
|
Subject: MIPS: ralink: manage low reset lines
|
||||||
|
|
||||||
|
Reset lines with indices smaller than 8 are currently considered invalid
|
||||||
|
by the rt2880-reset reset controller.
|
||||||
|
|
||||||
|
The MT7621 SoC uses a number of these low reset lines. The DTS defines
|
||||||
|
reset lines "hsdma", "fe", and "mcm" with respective values 5, 6, and 2.
|
||||||
|
As a result of the above restriction, these resets cannot be asserted or
|
||||||
|
de-asserted by the reset controller. In cases where the bootloader does
|
||||||
|
not de-assert these lines, this results in e.g. the MT7621's internal
|
||||||
|
switch staying in reset.
|
||||||
|
|
||||||
|
Change the reset controller to only ignore the system reset, so all
|
||||||
|
reset lines with index greater than 0 are considered valid.
|
||||||
|
|
||||||
|
Signed-off-by: Sander Vanheule <sander@svanheule.net>
|
||||||
|
Acked-by: John Crispin <john@phrozen.org>
|
||||||
|
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
|
||||||
|
---
|
||||||
|
arch/mips/ralink/reset.c | 4 ++--
|
||||||
|
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
--- a/arch/mips/ralink/reset.c
|
||||||
|
+++ b/arch/mips/ralink/reset.c
|
||||||
|
@@ -27,7 +27,7 @@ static int ralink_assert_device(struct r
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
- if (id < 8)
|
||||||
|
+ if (id == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
val = rt_sysc_r32(SYSC_REG_RESET_CTRL);
|
||||||
|
@@ -42,7 +42,7 @@ static int ralink_deassert_device(struct
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
- if (id < 8)
|
||||||
|
+ if (id == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
val = rt_sysc_r32(SYSC_REG_RESET_CTRL);
|
97
target/linux/ramips/patches-5.10/0200-linkit_bootstrap.patch
Normal file
97
target/linux/ramips/patches-5.10/0200-linkit_bootstrap.patch
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
--- a/drivers/misc/Makefile
|
||||||
|
+++ b/drivers/misc/Makefile
|
||||||
|
@@ -52,6 +52,7 @@ obj-$(CONFIG_ECHO) += echo/
|
||||||
|
obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
|
||||||
|
obj-$(CONFIG_CXL_BASE) += cxl/
|
||||||
|
obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o
|
||||||
|
+obj-$(CONFIG_SOC_MT7620) += linkit.o
|
||||||
|
obj-$(CONFIG_OCXL) += ocxl/
|
||||||
|
obj-y += cardreader/
|
||||||
|
obj-$(CONFIG_PVPANIC) += pvpanic.o
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/drivers/misc/linkit.c
|
||||||
|
@@ -0,0 +1,84 @@
|
||||||
|
+/*
|
||||||
|
+ * This program is free software; you can redistribute it and/or modify
|
||||||
|
+ * it under the terms of the GNU General Public License version 2 as
|
||||||
|
+ * publishhed by the Free Software Foundation.
|
||||||
|
+ *
|
||||||
|
+ * Copyright (C) 2015 John Crispin <blogic@openwrt.org>
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <linux/module.h>
|
||||||
|
+#include <linux/platform_device.h>
|
||||||
|
+#include <linux/of.h>
|
||||||
|
+#include <linux/mtd/mtd.h>
|
||||||
|
+#include <linux/gpio.h>
|
||||||
|
+
|
||||||
|
+#define LINKIT_LATCH_GPIO 11
|
||||||
|
+
|
||||||
|
+struct linkit_hw_data {
|
||||||
|
+ char board[16];
|
||||||
|
+ char rev[16];
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static void sanify_string(char *s)
|
||||||
|
+{
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < 15; i++)
|
||||||
|
+ if (s[i] <= 0x20)
|
||||||
|
+ s[i] = '\0';
|
||||||
|
+ s[15] = '\0';
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int linkit_probe(struct platform_device *pdev)
|
||||||
|
+{
|
||||||
|
+ struct linkit_hw_data hw;
|
||||||
|
+ struct mtd_info *mtd;
|
||||||
|
+ size_t retlen;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ mtd = get_mtd_device_nm("factory");
|
||||||
|
+ if (IS_ERR(mtd))
|
||||||
|
+ return PTR_ERR(mtd);
|
||||||
|
+
|
||||||
|
+ ret = mtd_read(mtd, 0x400, sizeof(hw), &retlen, (u_char *) &hw);
|
||||||
|
+ put_mtd_device(mtd);
|
||||||
|
+
|
||||||
|
+ sanify_string(hw.board);
|
||||||
|
+ sanify_string(hw.rev);
|
||||||
|
+
|
||||||
|
+ dev_info(&pdev->dev, "Version : %s\n", hw.board);
|
||||||
|
+ dev_info(&pdev->dev, "Revision : %s\n", hw.rev);
|
||||||
|
+
|
||||||
|
+ if (!strcmp(hw.board, "LINKITS7688")) {
|
||||||
|
+ dev_info(&pdev->dev, "setting up bootstrap latch\n");
|
||||||
|
+
|
||||||
|
+ if (devm_gpio_request(&pdev->dev, LINKIT_LATCH_GPIO, "bootstrap")) {
|
||||||
|
+ dev_err(&pdev->dev, "failed to setup bootstrap gpio\n");
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
+ gpio_direction_output(LINKIT_LATCH_GPIO, 0);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static const struct of_device_id linkit_match[] = {
|
||||||
|
+ { .compatible = "mediatek,linkit" },
|
||||||
|
+ {},
|
||||||
|
+};
|
||||||
|
+MODULE_DEVICE_TABLE(of, linkit_match);
|
||||||
|
+
|
||||||
|
+static struct platform_driver linkit_driver = {
|
||||||
|
+ .probe = linkit_probe,
|
||||||
|
+ .driver = {
|
||||||
|
+ .name = "mtk-linkit",
|
||||||
|
+ .owner = THIS_MODULE,
|
||||||
|
+ .of_match_table = linkit_match,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+int __init linkit_init(void)
|
||||||
|
+{
|
||||||
|
+ return platform_driver_register(&linkit_driver);
|
||||||
|
+}
|
||||||
|
+late_initcall_sync(linkit_init);
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,85 @@
|
|||||||
|
From 3d5f4da8296b23eb3abf8b13122b0d06a215e79c Mon Sep 17 00:00:00 2001
|
||||||
|
From: Weijie Gao <weijie.gao@mediatek.com>
|
||||||
|
Date: Wed, 1 Apr 2020 02:07:59 +0800
|
||||||
|
Subject: [PATCH 2/2] dt-bindings: add documentation for mt7621-nand driver
|
||||||
|
|
||||||
|
This patch adds documentation for MediaTek MT7621 NAND flash controller
|
||||||
|
driver.
|
||||||
|
|
||||||
|
Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
|
||||||
|
---
|
||||||
|
.../bindings/mtd/mediatek,mt7621-nfc.yaml | 68 ++++++++++++++++++++++
|
||||||
|
1 file changed, 68 insertions(+)
|
||||||
|
create mode 100644 Documentation/devicetree/bindings/mtd/mediatek,mt7621-nfc.yaml
|
||||||
|
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/Documentation/devicetree/bindings/mtd/mediatek,mt7621-nfc.yaml
|
||||||
|
@@ -0,0 +1,68 @@
|
||||||
|
+# SPDX-License-Identifier: GPL-2.0
|
||||||
|
+%YAML 1.2
|
||||||
|
+---
|
||||||
|
+$id: http://devicetree.org/schemas/mtd/mediatek,mt7621-nfc.yaml#
|
||||||
|
+$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
+
|
||||||
|
+title: MediaTek MT7621 SoC NAND Flash Controller (NFC) DT binding
|
||||||
|
+
|
||||||
|
+maintainers:
|
||||||
|
+ - Weijie Gao <weijie.gao@mediatek.com>
|
||||||
|
+
|
||||||
|
+description: |
|
||||||
|
+ This driver uses a single node to describe both NAND Flash controller
|
||||||
|
+ interface (NFI) and ECC engine for MT7621 SoC.
|
||||||
|
+ MT7621 supports only one chip select.
|
||||||
|
+
|
||||||
|
+properties:
|
||||||
|
+ "#address-cells": false
|
||||||
|
+ "#size-cells": false
|
||||||
|
+
|
||||||
|
+ compatible:
|
||||||
|
+ enum:
|
||||||
|
+ - mediatek,mt7621-nfc
|
||||||
|
+
|
||||||
|
+ reg:
|
||||||
|
+ items:
|
||||||
|
+ - description: Register base of NFI core
|
||||||
|
+ - description: Register base of ECC engine
|
||||||
|
+
|
||||||
|
+ reg-names:
|
||||||
|
+ items:
|
||||||
|
+ - const: nfi
|
||||||
|
+ - const: ecc
|
||||||
|
+
|
||||||
|
+ clocks:
|
||||||
|
+ items:
|
||||||
|
+ - description: Source clock for NFI core, fixed 125MHz
|
||||||
|
+
|
||||||
|
+ clock-names:
|
||||||
|
+ items:
|
||||||
|
+ - const: nfi_clk
|
||||||
|
+
|
||||||
|
+required:
|
||||||
|
+ - compatible
|
||||||
|
+ - reg
|
||||||
|
+ - reg-names
|
||||||
|
+ - clocks
|
||||||
|
+ - clock-names
|
||||||
|
+
|
||||||
|
+examples:
|
||||||
|
+ - |
|
||||||
|
+ nficlock: nficlock {
|
||||||
|
+ #clock-cells = <0>;
|
||||||
|
+ compatible = "fixed-clock";
|
||||||
|
+
|
||||||
|
+ clock-frequency = <125000000>;
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ nand@1e003000 {
|
||||||
|
+ compatible = "mediatek,mt7621-nfc";
|
||||||
|
+
|
||||||
|
+ reg = <0x1e003000 0x800
|
||||||
|
+ 0x1e003800 0x800>;
|
||||||
|
+ reg-names = "nfi", "ecc";
|
||||||
|
+
|
||||||
|
+ clocks = <&nficlock>;
|
||||||
|
+ clock-names = "nfi_clk";
|
||||||
|
+ };
|
@ -0,0 +1,61 @@
|
|||||||
|
There is a variant of MT7621 which contains only one CPU core instead of 2.
|
||||||
|
This is not reflected in the config register, so the kernel detects more
|
||||||
|
physical cores, which leads to a hang on SMP bringup.
|
||||||
|
Add a hack to detect missing cores.
|
||||||
|
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
|
||||||
|
--- a/arch/mips/kernel/smp-cps.c
|
||||||
|
+++ b/arch/mips/kernel/smp-cps.c
|
||||||
|
@@ -43,6 +43,11 @@ static unsigned core_vpe_count(unsigned
|
||||||
|
return mips_cps_numvps(cluster, core);
|
||||||
|
}
|
||||||
|
|
||||||
|
+bool __weak plat_cpu_core_present(int core)
|
||||||
|
+{
|
||||||
|
+ return true;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void __init cps_smp_setup(void)
|
||||||
|
{
|
||||||
|
unsigned int nclusters, ncores, nvpes, core_vpes;
|
||||||
|
@@ -60,6 +65,8 @@ static void __init cps_smp_setup(void)
|
||||||
|
|
||||||
|
ncores = mips_cps_numcores(cl);
|
||||||
|
for (c = 0; c < ncores; c++) {
|
||||||
|
+ if (!plat_cpu_core_present(c))
|
||||||
|
+ continue;
|
||||||
|
core_vpes = core_vpe_count(cl, c);
|
||||||
|
|
||||||
|
if (c > 0)
|
||||||
|
--- a/arch/mips/ralink/mt7621.c
|
||||||
|
+++ b/arch/mips/ralink/mt7621.c
|
||||||
|
@@ -13,6 +13,7 @@
|
||||||
|
#include <asm/mips-cps.h>
|
||||||
|
#include <asm/mach-ralink/ralink_regs.h>
|
||||||
|
#include <asm/mach-ralink/mt7621.h>
|
||||||
|
+#include <asm/mips-boards/launch.h>
|
||||||
|
|
||||||
|
#include <pinmux.h>
|
||||||
|
|
||||||
|
@@ -160,6 +161,20 @@ void __init ralink_of_remap(void)
|
||||||
|
panic("Failed to remap core resources");
|
||||||
|
}
|
||||||
|
|
||||||
|
+bool plat_cpu_core_present(int core)
|
||||||
|
+{
|
||||||
|
+ struct cpulaunch *launch = (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH);
|
||||||
|
+
|
||||||
|
+ if (!core)
|
||||||
|
+ return true;
|
||||||
|
+ launch += core * 2; /* 2 VPEs per core */
|
||||||
|
+ if (!(launch->flags & LAUNCH_FREADY))
|
||||||
|
+ return false;
|
||||||
|
+ if (launch->flags & (LAUNCH_FGO | LAUNCH_FGONE))
|
||||||
|
+ return false;
|
||||||
|
+ return true;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void prom_soc_init(struct ralink_soc_info *soc_info)
|
||||||
|
{
|
||||||
|
void __iomem *sysc = (void __iomem *) KSEG1ADDR(MT7621_SYSC_BASE);
|
87
target/linux/ramips/patches-5.10/101-mt7621-timer.patch
Normal file
87
target/linux/ramips/patches-5.10/101-mt7621-timer.patch
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
--- a/arch/mips/ralink/mt7621.c
|
||||||
|
+++ b/arch/mips/ralink/mt7621.c
|
||||||
|
@@ -7,6 +7,7 @@
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
+#include <linux/jiffies.h>
|
||||||
|
|
||||||
|
#include <asm/mipsregs.h>
|
||||||
|
#include <asm/smp-ops.h>
|
||||||
|
@@ -14,6 +15,7 @@
|
||||||
|
#include <asm/mach-ralink/ralink_regs.h>
|
||||||
|
#include <asm/mach-ralink/mt7621.h>
|
||||||
|
#include <asm/mips-boards/launch.h>
|
||||||
|
+#include <asm/delay.h>
|
||||||
|
|
||||||
|
#include <pinmux.h>
|
||||||
|
|
||||||
|
@@ -175,6 +177,58 @@ bool plat_cpu_core_present(int core)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
+#define LPS_PREC 8
|
||||||
|
+/*
|
||||||
|
+* Re-calibration lpj(loop-per-jiffy).
|
||||||
|
+* (derived from kernel/calibrate.c)
|
||||||
|
+*/
|
||||||
|
+static int udelay_recal(void)
|
||||||
|
+{
|
||||||
|
+ unsigned int i, lpj = 0;
|
||||||
|
+ unsigned long ticks, loopbit;
|
||||||
|
+ int lps_precision = LPS_PREC;
|
||||||
|
+
|
||||||
|
+ lpj = (1<<12);
|
||||||
|
+
|
||||||
|
+ while ((lpj <<= 1) != 0) {
|
||||||
|
+ /* wait for "start of" clock tick */
|
||||||
|
+ ticks = jiffies;
|
||||||
|
+ while (ticks == jiffies)
|
||||||
|
+ /* nothing */;
|
||||||
|
+
|
||||||
|
+ /* Go .. */
|
||||||
|
+ ticks = jiffies;
|
||||||
|
+ __delay(lpj);
|
||||||
|
+ ticks = jiffies - ticks;
|
||||||
|
+ if (ticks)
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Do a binary approximation to get lpj set to
|
||||||
|
+ * equal one clock (up to lps_precision bits)
|
||||||
|
+ */
|
||||||
|
+ lpj >>= 1;
|
||||||
|
+ loopbit = lpj;
|
||||||
|
+ while (lps_precision-- && (loopbit >>= 1)) {
|
||||||
|
+ lpj |= loopbit;
|
||||||
|
+ ticks = jiffies;
|
||||||
|
+ while (ticks == jiffies)
|
||||||
|
+ /* nothing */;
|
||||||
|
+ ticks = jiffies;
|
||||||
|
+ __delay(lpj);
|
||||||
|
+ if (jiffies != ticks) /* longer than 1 tick */
|
||||||
|
+ lpj &= ~loopbit;
|
||||||
|
+ }
|
||||||
|
+ printk(KERN_INFO "%d CPUs re-calibrate udelay(lpj = %d)\n", NR_CPUS, lpj);
|
||||||
|
+
|
||||||
|
+ for(i=0; i< NR_CPUS; i++)
|
||||||
|
+ cpu_data[i].udelay_val = lpj;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+device_initcall(udelay_recal);
|
||||||
|
+
|
||||||
|
void prom_soc_init(struct ralink_soc_info *soc_info)
|
||||||
|
{
|
||||||
|
void __iomem *sysc = (void __iomem *) KSEG1ADDR(MT7621_SYSC_BASE);
|
||||||
|
--- a/arch/mips/ralink/Kconfig
|
||||||
|
+++ b/arch/mips/ralink/Kconfig
|
||||||
|
@@ -58,6 +58,7 @@ choice
|
||||||
|
select CLKSRC_MIPS_GIC
|
||||||
|
select HAVE_PCI if PCI_MT7621
|
||||||
|
select WEAK_REORDERING_BEYOND_LLSC
|
||||||
|
+ select GENERIC_CLOCKEVENTS_BROADCAST
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
choice
|
@ -0,0 +1,224 @@
|
|||||||
|
--- a/arch/mips/include/asm/mach-ralink/mt7621.h
|
||||||
|
+++ b/arch/mips/include/asm/mach-ralink/mt7621.h
|
||||||
|
@@ -17,6 +17,10 @@
|
||||||
|
#define SYSC_REG_CHIP_REV 0x0c
|
||||||
|
#define SYSC_REG_SYSTEM_CONFIG0 0x10
|
||||||
|
#define SYSC_REG_SYSTEM_CONFIG1 0x14
|
||||||
|
+#define SYSC_REG_CLKCFG0 0x2c
|
||||||
|
+#define SYSC_REG_CUR_CLK_STS 0x44
|
||||||
|
+
|
||||||
|
+#define MEMC_REG_CPU_PLL 0x648
|
||||||
|
|
||||||
|
#define CHIP_REV_PKG_MASK 0x1
|
||||||
|
#define CHIP_REV_PKG_SHIFT 16
|
||||||
|
@@ -24,6 +28,22 @@
|
||||||
|
#define CHIP_REV_VER_SHIFT 8
|
||||||
|
#define CHIP_REV_ECO_MASK 0xf
|
||||||
|
|
||||||
|
+#define XTAL_MODE_SEL_MASK 0x7
|
||||||
|
+#define XTAL_MODE_SEL_SHIFT 6
|
||||||
|
+
|
||||||
|
+#define CPU_CLK_SEL_MASK 0x3
|
||||||
|
+#define CPU_CLK_SEL_SHIFT 30
|
||||||
|
+
|
||||||
|
+#define CUR_CPU_FDIV_MASK 0x1f
|
||||||
|
+#define CUR_CPU_FDIV_SHIFT 8
|
||||||
|
+#define CUR_CPU_FFRAC_MASK 0x1f
|
||||||
|
+#define CUR_CPU_FFRAC_SHIFT 0
|
||||||
|
+
|
||||||
|
+#define CPU_PLL_PREDIV_MASK 0x3
|
||||||
|
+#define CPU_PLL_PREDIV_SHIFT 12
|
||||||
|
+#define CPU_PLL_FBDIV_MASK 0x7f
|
||||||
|
+#define CPU_PLL_FBDIV_SHIFT 4
|
||||||
|
+
|
||||||
|
#define MT7621_DRAM_BASE 0x0
|
||||||
|
#define MT7621_DDR2_SIZE_MIN 32
|
||||||
|
#define MT7621_DDR2_SIZE_MAX 256
|
||||||
|
--- a/arch/mips/ralink/mt7621.c
|
||||||
|
+++ b/arch/mips/ralink/mt7621.c
|
||||||
|
@@ -8,6 +8,10 @@
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/jiffies.h>
|
||||||
|
+#include <linux/clk.h>
|
||||||
|
+#include <linux/clkdev.h>
|
||||||
|
+#include <linux/clk-provider.h>
|
||||||
|
+#include <dt-bindings/clock/mt7621-clk.h>
|
||||||
|
|
||||||
|
#include <asm/mipsregs.h>
|
||||||
|
#include <asm/smp-ops.h>
|
||||||
|
@@ -16,16 +20,12 @@
|
||||||
|
#include <asm/mach-ralink/mt7621.h>
|
||||||
|
#include <asm/mips-boards/launch.h>
|
||||||
|
#include <asm/delay.h>
|
||||||
|
+#include <asm/time.h>
|
||||||
|
|
||||||
|
#include <pinmux.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
-#define SYSC_REG_SYSCFG 0x10
|
||||||
|
-#define SYSC_REG_CPLL_CLKCFG0 0x2c
|
||||||
|
-#define SYSC_REG_CUR_CLK_STS 0x44
|
||||||
|
-#define CPU_CLK_SEL (BIT(30) | BIT(31))
|
||||||
|
-
|
||||||
|
#define MT7621_GPIO_MODE_UART1 1
|
||||||
|
#define MT7621_GPIO_MODE_I2C 2
|
||||||
|
#define MT7621_GPIO_MODE_UART3_MASK 0x3
|
||||||
|
@@ -111,49 +111,89 @@ static struct rt2880_pmx_group mt7621_pi
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
+static struct clk *clks[MT7621_CLK_MAX];
|
||||||
|
+static struct clk_onecell_data clk_data = {
|
||||||
|
+ .clks = clks,
|
||||||
|
+ .clk_num = ARRAY_SIZE(clks),
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
phys_addr_t mips_cpc_default_phys_base(void)
|
||||||
|
{
|
||||||
|
panic("Cannot detect cpc address");
|
||||||
|
}
|
||||||
|
|
||||||
|
-void __init ralink_clk_init(void)
|
||||||
|
+static struct clk *__init mt7621_add_sys_clkdev(
|
||||||
|
+ const char *id, unsigned long rate)
|
||||||
|
{
|
||||||
|
- int cpu_fdiv = 0;
|
||||||
|
- int cpu_ffrac = 0;
|
||||||
|
- int fbdiv = 0;
|
||||||
|
- u32 clk_sts, syscfg;
|
||||||
|
- u8 clk_sel = 0, xtal_mode;
|
||||||
|
- u32 cpu_clk;
|
||||||
|
+ struct clk *clk;
|
||||||
|
+ int err;
|
||||||
|
+
|
||||||
|
+ clk = clk_register_fixed_rate(NULL, id, NULL, 0, rate);
|
||||||
|
+ if (IS_ERR(clk))
|
||||||
|
+ panic("failed to allocate %s clock structure", id);
|
||||||
|
+
|
||||||
|
+ err = clk_register_clkdev(clk, id, NULL);
|
||||||
|
+ if (err)
|
||||||
|
+ panic("unable to register %s clock device", id);
|
||||||
|
|
||||||
|
- if ((rt_sysc_r32(SYSC_REG_CPLL_CLKCFG0) & CPU_CLK_SEL) != 0)
|
||||||
|
- clk_sel = 1;
|
||||||
|
+ return clk;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void __init ralink_clk_init(void)
|
||||||
|
+{
|
||||||
|
+ u32 syscfg, xtal_sel, clkcfg, clk_sel, curclk, ffiv, ffrac;
|
||||||
|
+ u32 pll, prediv, fbdiv;
|
||||||
|
+ u32 xtal_clk, cpu_clk, bus_clk;
|
||||||
|
+ const static u32 prediv_tbl[] = {0, 1, 2, 2};
|
||||||
|
+
|
||||||
|
+ syscfg = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0);
|
||||||
|
+ xtal_sel = (syscfg >> XTAL_MODE_SEL_SHIFT) & XTAL_MODE_SEL_MASK;
|
||||||
|
+
|
||||||
|
+ clkcfg = rt_sysc_r32(SYSC_REG_CLKCFG0);
|
||||||
|
+ clk_sel = (clkcfg >> CPU_CLK_SEL_SHIFT) & CPU_CLK_SEL_MASK;
|
||||||
|
+
|
||||||
|
+ curclk = rt_sysc_r32(SYSC_REG_CUR_CLK_STS);
|
||||||
|
+ ffiv = (curclk >> CUR_CPU_FDIV_SHIFT) & CUR_CPU_FDIV_MASK;
|
||||||
|
+ ffrac = (curclk >> CUR_CPU_FFRAC_SHIFT) & CUR_CPU_FFRAC_MASK;
|
||||||
|
+
|
||||||
|
+ if (xtal_sel <= 2)
|
||||||
|
+ xtal_clk = 20 * 1000 * 1000;
|
||||||
|
+ else if (xtal_sel <= 5)
|
||||||
|
+ xtal_clk = 40 * 1000 * 1000;
|
||||||
|
+ else
|
||||||
|
+ xtal_clk = 25 * 1000 * 1000;
|
||||||
|
|
||||||
|
switch (clk_sel) {
|
||||||
|
case 0:
|
||||||
|
- clk_sts = rt_sysc_r32(SYSC_REG_CUR_CLK_STS);
|
||||||
|
- cpu_fdiv = ((clk_sts >> 8) & 0x1F);
|
||||||
|
- cpu_ffrac = (clk_sts & 0x1F);
|
||||||
|
- cpu_clk = (500 * cpu_ffrac / cpu_fdiv) * 1000 * 1000;
|
||||||
|
+ cpu_clk = 500 * 1000 * 1000;
|
||||||
|
break;
|
||||||
|
-
|
||||||
|
case 1:
|
||||||
|
- fbdiv = ((rt_sysc_r32(0x648) >> 4) & 0x7F) + 1;
|
||||||
|
- syscfg = rt_sysc_r32(SYSC_REG_SYSCFG);
|
||||||
|
- xtal_mode = (syscfg >> 6) & 0x7;
|
||||||
|
- if (xtal_mode >= 6) {
|
||||||
|
- /* 25Mhz Xtal */
|
||||||
|
- cpu_clk = 25 * fbdiv * 1000 * 1000;
|
||||||
|
- } else if (xtal_mode >= 3) {
|
||||||
|
- /* 40Mhz Xtal */
|
||||||
|
- cpu_clk = 40 * fbdiv * 1000 * 1000;
|
||||||
|
- } else {
|
||||||
|
- /* 20Mhz Xtal */
|
||||||
|
- cpu_clk = 20 * fbdiv * 1000 * 1000;
|
||||||
|
- }
|
||||||
|
+ pll = rt_memc_r32(MEMC_REG_CPU_PLL);
|
||||||
|
+ fbdiv = (pll >> CPU_PLL_FBDIV_SHIFT) & CPU_PLL_FBDIV_MASK;
|
||||||
|
+ prediv = (pll >> CPU_PLL_PREDIV_SHIFT) & CPU_PLL_PREDIV_MASK;
|
||||||
|
+ cpu_clk = ((fbdiv + 1) * xtal_clk) >> prediv_tbl[prediv];
|
||||||
|
break;
|
||||||
|
+ default:
|
||||||
|
+ cpu_clk = xtal_clk;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ cpu_clk = cpu_clk / ffiv * ffrac;
|
||||||
|
+ bus_clk = cpu_clk / 4;
|
||||||
|
+
|
||||||
|
+ clks[MT7621_CLK_CPU] = mt7621_add_sys_clkdev("cpu", cpu_clk);
|
||||||
|
+ clks[MT7621_CLK_BUS] = mt7621_add_sys_clkdev("bus", bus_clk);
|
||||||
|
+
|
||||||
|
+ pr_info("CPU Clock: %dMHz\n", cpu_clk / 1000000);
|
||||||
|
+ mips_hpt_frequency = cpu_clk / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void __init mt7621_clocks_init_dt(struct device_node *np)
|
||||||
|
+{
|
||||||
|
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+CLK_OF_DECLARE(ar7100, "mediatek,mt7621-pll", mt7621_clocks_init_dt);
|
||||||
|
+
|
||||||
|
void __init ralink_of_remap(void)
|
||||||
|
{
|
||||||
|
rt_sysc_membase = plat_of_remap_node("mtk,mt7621-sysc");
|
||||||
|
--- a/arch/mips/ralink/timer-gic.c
|
||||||
|
+++ b/arch/mips/ralink/timer-gic.c
|
||||||
|
@@ -9,14 +9,14 @@
|
||||||
|
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/clk-provider.h>
|
||||||
|
-#include <linux/clocksource.h>
|
||||||
|
+#include <asm/time.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
void __init plat_time_init(void)
|
||||||
|
{
|
||||||
|
ralink_of_remap();
|
||||||
|
-
|
||||||
|
+ ralink_clk_init();
|
||||||
|
of_clk_init(NULL);
|
||||||
|
timer_probe();
|
||||||
|
}
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/include/dt-bindings/clock/mt7621-clk.h
|
||||||
|
@@ -0,0 +1,18 @@
|
||||||
|
+/*
|
||||||
|
+ * Copyright (C) 2018 Weijie Gao <hackpascal@gmail.com>
|
||||||
|
+ *
|
||||||
|
+ * This program is free software; you can redistribute it and/or modify
|
||||||
|
+ * it under the terms of the GNU General Public License version 2 as
|
||||||
|
+ * published by the Free Software Foundation.
|
||||||
|
+ *
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#ifndef __DT_BINDINGS_MT7621_CLK_H
|
||||||
|
+#define __DT_BINDINGS_MT7621_CLK_H
|
||||||
|
+
|
||||||
|
+#define MT7621_CLK_CPU 0
|
||||||
|
+#define MT7621_CLK_BUS 1
|
||||||
|
+
|
||||||
|
+#define MT7621_CLK_MAX 2
|
||||||
|
+
|
||||||
|
+#endif /* __DT_BINDINGS_MT7621_CLK_H */
|
125
target/linux/ramips/patches-5.10/105-mt7621-memory-detect.patch
Normal file
125
target/linux/ramips/patches-5.10/105-mt7621-memory-detect.patch
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
From b5a52351a66f3c2a7a207548aa87d78ff2d336c0 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Chuanhong Guo <gch981213@gmail.com>
|
||||||
|
Date: Wed, 10 Jul 2019 00:24:48 +0800
|
||||||
|
Subject: [PATCH] MIPS: ralink: mt7621: add memory detection support
|
||||||
|
|
||||||
|
mt7621 has the following memory map:
|
||||||
|
0x0-0x1c000000: lower 448m memory
|
||||||
|
0x1c000000-0x2000000: peripheral registers
|
||||||
|
0x20000000-0x2400000: higher 64m memory
|
||||||
|
|
||||||
|
detect_memory_region in arch/mips/kernel/setup.c only add the first
|
||||||
|
memory region and isn't suitable for 512m memory detection because
|
||||||
|
it may accidentally read the memory area for peripheral registers.
|
||||||
|
|
||||||
|
This commit adds memory detection capability for mt7621:
|
||||||
|
1. add the highmem area when 512m is detected.
|
||||||
|
2. guard memcmp from accessing peripheral registers:
|
||||||
|
This only happens when some weird user decided to change
|
||||||
|
kernel load address to 256m or higher address. Since this
|
||||||
|
is a quite unusual case, we just skip 512m testing and return
|
||||||
|
256m as memory size.
|
||||||
|
|
||||||
|
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
|
||||||
|
---
|
||||||
|
arch/mips/include/asm/mach-ralink/mt7621.h | 7 ++---
|
||||||
|
arch/mips/ralink/mt7621.c | 30 +++++++++++++++++++---
|
||||||
|
2 files changed, 30 insertions(+), 7 deletions(-)
|
||||||
|
|
||||||
|
--- a/arch/mips/include/asm/mach-ralink/mt7621.h
|
||||||
|
+++ b/arch/mips/include/asm/mach-ralink/mt7621.h
|
||||||
|
@@ -44,9 +44,10 @@
|
||||||
|
#define CPU_PLL_FBDIV_MASK 0x7f
|
||||||
|
#define CPU_PLL_FBDIV_SHIFT 4
|
||||||
|
|
||||||
|
-#define MT7621_DRAM_BASE 0x0
|
||||||
|
-#define MT7621_DDR2_SIZE_MIN 32
|
||||||
|
-#define MT7621_DDR2_SIZE_MAX 256
|
||||||
|
+#define MT7621_LOWMEM_BASE 0x0
|
||||||
|
+#define MT7621_LOWMEM_MAX_SIZE 0x1C000000
|
||||||
|
+#define MT7621_HIGHMEM_BASE 0x20000000
|
||||||
|
+#define MT7621_HIGHMEM_SIZE 0x4000000
|
||||||
|
|
||||||
|
#define MT7621_CHIP_NAME0 0x3637544D
|
||||||
|
#define MT7621_CHIP_NAME1 0x20203132
|
||||||
|
--- a/arch/mips/ralink/mt7621.c
|
||||||
|
+++ b/arch/mips/ralink/mt7621.c
|
||||||
|
@@ -13,6 +13,7 @@
|
||||||
|
#include <linux/clk-provider.h>
|
||||||
|
#include <dt-bindings/clock/mt7621-clk.h>
|
||||||
|
|
||||||
|
+#include <asm/bootinfo.h>
|
||||||
|
#include <asm/mipsregs.h>
|
||||||
|
#include <asm/smp-ops.h>
|
||||||
|
#include <asm/mips-cps.h>
|
||||||
|
@@ -55,6 +56,8 @@
|
||||||
|
#define MT7621_GPIO_MODE_SDHCI_SHIFT 18
|
||||||
|
#define MT7621_GPIO_MODE_SDHCI_GPIO 1
|
||||||
|
|
||||||
|
+static void *detect_magic __initdata = detect_memory_region;
|
||||||
|
+
|
||||||
|
static struct rt2880_pmx_func uart1_grp[] = { FUNC("uart1", 0, 1, 2) };
|
||||||
|
static struct rt2880_pmx_func i2c_grp[] = { FUNC("i2c", 0, 3, 2) };
|
||||||
|
static struct rt2880_pmx_func uart3_grp[] = {
|
||||||
|
@@ -139,6 +142,28 @@ static struct clk *__init mt7621_add_sys
|
||||||
|
return clk;
|
||||||
|
}
|
||||||
|
|
||||||
|
+void __init mt7621_memory_detect(void)
|
||||||
|
+{
|
||||||
|
+ void *dm = &detect_magic;
|
||||||
|
+ phys_addr_t size;
|
||||||
|
+
|
||||||
|
+ for (size = 32 * SZ_1M; size < 256 * SZ_1M; size <<= 1) {
|
||||||
|
+ if (!memcmp(dm, dm + size, sizeof(detect_magic)))
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if ((size == 256 * SZ_1M) &&
|
||||||
|
+ (CPHYSADDR(dm + size) < MT7621_LOWMEM_MAX_SIZE) &&
|
||||||
|
+ memcmp(dm, dm + size, sizeof(detect_magic))) {
|
||||||
|
+ add_memory_region(MT7621_LOWMEM_BASE, MT7621_LOWMEM_MAX_SIZE,
|
||||||
|
+ BOOT_MEM_RAM);
|
||||||
|
+ add_memory_region(MT7621_HIGHMEM_BASE, MT7621_HIGHMEM_SIZE,
|
||||||
|
+ BOOT_MEM_RAM);
|
||||||
|
+ } else {
|
||||||
|
+ add_memory_region(MT7621_LOWMEM_BASE, size, BOOT_MEM_RAM);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void __init ralink_clk_init(void)
|
||||||
|
{
|
||||||
|
u32 syscfg, xtal_sel, clkcfg, clk_sel, curclk, ffiv, ffrac;
|
||||||
|
@@ -317,10 +342,7 @@ void prom_soc_init(struct ralink_soc_inf
|
||||||
|
(rev >> CHIP_REV_VER_SHIFT) & CHIP_REV_VER_MASK,
|
||||||
|
(rev & CHIP_REV_ECO_MASK));
|
||||||
|
|
||||||
|
- soc_info->mem_size_min = MT7621_DDR2_SIZE_MIN;
|
||||||
|
- soc_info->mem_size_max = MT7621_DDR2_SIZE_MAX;
|
||||||
|
- soc_info->mem_base = MT7621_DRAM_BASE;
|
||||||
|
-
|
||||||
|
+ soc_info->mem_detect = mt7621_memory_detect;
|
||||||
|
rt2880_pinmux_data = mt7621_pinmux_data;
|
||||||
|
|
||||||
|
|
||||||
|
--- a/arch/mips/ralink/common.h
|
||||||
|
+++ b/arch/mips/ralink/common.h
|
||||||
|
@@ -17,6 +17,7 @@ struct ralink_soc_info {
|
||||||
|
unsigned long mem_size;
|
||||||
|
unsigned long mem_size_min;
|
||||||
|
unsigned long mem_size_max;
|
||||||
|
+ void (*mem_detect)(void);
|
||||||
|
};
|
||||||
|
extern struct ralink_soc_info soc_info;
|
||||||
|
|
||||||
|
--- a/arch/mips/ralink/of.c
|
||||||
|
+++ b/arch/mips/ralink/of.c
|
||||||
|
@@ -87,6 +87,8 @@ void __init plat_mem_setup(void)
|
||||||
|
of_scan_flat_dt(early_init_dt_find_memory, NULL);
|
||||||
|
if (memory_dtb)
|
||||||
|
of_scan_flat_dt(early_init_dt_scan_memory, NULL);
|
||||||
|
+ else if (soc_info.mem_detect)
|
||||||
|
+ soc_info.mem_detect();
|
||||||
|
else if (soc_info.mem_size)
|
||||||
|
add_memory_region(soc_info.mem_base, soc_info.mem_size * SZ_1M,
|
||||||
|
BOOT_MEM_RAM);
|
@ -0,0 +1,15 @@
|
|||||||
|
--- a/arch/mips/ralink/irq-gic.c
|
||||||
|
+++ b/arch/mips/ralink/irq-gic.c
|
||||||
|
@@ -13,6 +13,12 @@
|
||||||
|
|
||||||
|
int get_c0_perfcount_int(void)
|
||||||
|
{
|
||||||
|
+ /*
|
||||||
|
+ * Performance counter events are routed through GIC.
|
||||||
|
+ * Prevent them from firing on CPU IRQ7 as well
|
||||||
|
+ */
|
||||||
|
+ clear_c0_status(IE_SW0 << 7);
|
||||||
|
+
|
||||||
|
return gic_get_c0_perfcount_int();
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
|
@ -0,0 +1,85 @@
|
|||||||
|
From 5d7b644aad721ecca20bd8976b38fb243fdc84f9 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Chuanhong Guo <gch981213@gmail.com>
|
||||||
|
Date: Sun, 15 Mar 2020 20:13:37 +0800
|
||||||
|
Subject: [PATCH] gpio: mmio: introduce BGPIOF_NO_SET_ON_INPUT
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
Some gpio controllers ignores pin value writing when that pin is
|
||||||
|
configured as input mode. As a result, bgpio_dir_out should set
|
||||||
|
pin to output before configuring pin values or gpio pin values
|
||||||
|
can't be set up properly.
|
||||||
|
Introduce two variants of bgpio_dir_out: bgpio_dir_out_val_first
|
||||||
|
and bgpio_dir_out_dir_first, and assign direction_output according
|
||||||
|
to a new flag: BGPIOF_NO_SET_ON_INPUT.
|
||||||
|
|
||||||
|
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
|
||||||
|
Tested-by: René van Dorst <opensource@vdorst.com>
|
||||||
|
Reviewed-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
|
||||||
|
---
|
||||||
|
drivers/gpio/gpio-mmio.c | 23 +++++++++++++++++++----
|
||||||
|
include/linux/gpio/driver.h | 1 +
|
||||||
|
2 files changed, 20 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/gpio/gpio-mmio.c
|
||||||
|
+++ b/drivers/gpio/gpio-mmio.c
|
||||||
|
@@ -381,12 +381,10 @@ static int bgpio_get_dir(struct gpio_chi
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||||
|
+static void bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
- gc->set(gc, gpio, val);
|
||||||
|
-
|
||||||
|
spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||||
|
|
||||||
|
gc->bgpio_dir |= bgpio_line2mask(gc, gpio);
|
||||||
|
@@ -397,7 +395,21 @@ static int bgpio_dir_out(struct gpio_chi
|
||||||
|
gc->write_reg(gc->reg_dir_out, gc->bgpio_dir);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||||
|
+}
|
||||||
|
|
||||||
|
+static int bgpio_dir_out_dir_first(struct gpio_chip *gc, unsigned int gpio,
|
||||||
|
+ int val)
|
||||||
|
+{
|
||||||
|
+ bgpio_dir_out(gc, gpio, val);
|
||||||
|
+ gc->set(gc, gpio, val);
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int bgpio_dir_out_val_first(struct gpio_chip *gc, unsigned int gpio,
|
||||||
|
+ int val)
|
||||||
|
+{
|
||||||
|
+ gc->set(gc, gpio, val);
|
||||||
|
+ bgpio_dir_out(gc, gpio, val);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -530,7 +542,10 @@ static int bgpio_setup_direction(struct
|
||||||
|
if (dirout || dirin) {
|
||||||
|
gc->reg_dir_out = dirout;
|
||||||
|
gc->reg_dir_in = dirin;
|
||||||
|
- gc->direction_output = bgpio_dir_out;
|
||||||
|
+ if (flags & BGPIOF_NO_SET_ON_INPUT)
|
||||||
|
+ gc->direction_output = bgpio_dir_out_dir_first;
|
||||||
|
+ else
|
||||||
|
+ gc->direction_output = bgpio_dir_out_val_first;
|
||||||
|
gc->direction_input = bgpio_dir_in;
|
||||||
|
gc->get_direction = bgpio_get_dir;
|
||||||
|
} else {
|
||||||
|
--- a/include/linux/gpio/driver.h
|
||||||
|
+++ b/include/linux/gpio/driver.h
|
||||||
|
@@ -567,6 +567,7 @@ int bgpio_init(struct gpio_chip *gc, str
|
||||||
|
#define BGPIOF_BIG_ENDIAN_BYTE_ORDER BIT(3)
|
||||||
|
#define BGPIOF_READ_OUTPUT_REG_SET BIT(4) /* reg_set stores output value */
|
||||||
|
#define BGPIOF_NO_OUTPUT BIT(5) /* only input */
|
||||||
|
+#define BGPIOF_NO_SET_ON_INPUT BIT(6)
|
||||||
|
|
||||||
|
int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
|
||||||
|
irq_hw_number_t hwirq);
|
@ -0,0 +1,33 @@
|
|||||||
|
From ad65f02fd73e9a700f1693a4513ae923ca07beb0 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Chuanhong Guo <gch981213@gmail.com>
|
||||||
|
Date: Sun, 15 Mar 2020 20:13:38 +0800
|
||||||
|
Subject: [PATCH] gpio: mt7621: add BGPIOF_NO_SET_ON_INPUT flag
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
DSET/DCLR registers only works on output pins. Add corresponding
|
||||||
|
BGPIOF_NO_SET_ON_INPUT flag to bgpio_init call to fix direction_out
|
||||||
|
behavior.
|
||||||
|
|
||||||
|
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
|
||||||
|
Tested-by: René van Dorst <opensource@vdorst.com>
|
||||||
|
Reviewed-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
|
||||||
|
---
|
||||||
|
drivers/gpio/gpio-mt7621.c | 4 ++--
|
||||||
|
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/gpio/gpio-mt7621.c
|
||||||
|
+++ b/drivers/gpio/gpio-mt7621.c
|
||||||
|
@@ -227,8 +227,8 @@ mediatek_gpio_bank_probe(struct device *
|
||||||
|
ctrl = mtk->base + GPIO_REG_DCLR + (rg->bank * GPIO_BANK_STRIDE);
|
||||||
|
diro = mtk->base + GPIO_REG_CTRL + (rg->bank * GPIO_BANK_STRIDE);
|
||||||
|
|
||||||
|
- ret = bgpio_init(&rg->chip, dev, 4,
|
||||||
|
- dat, set, ctrl, diro, NULL, 0);
|
||||||
|
+ ret = bgpio_init(&rg->chip, dev, 4, dat, set, ctrl, diro, NULL,
|
||||||
|
+ BGPIOF_NO_SET_ON_INPUT);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "bgpio_init() failed\n");
|
||||||
|
return ret;
|
20
target/linux/ramips/patches-5.10/200-add-ralink-eth.patch
Normal file
20
target/linux/ramips/patches-5.10/200-add-ralink-eth.patch
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
--- a/drivers/net/ethernet/Kconfig
|
||||||
|
+++ b/drivers/net/ethernet/Kconfig
|
||||||
|
@@ -159,6 +159,7 @@ source "drivers/net/ethernet/pasemi/Kcon
|
||||||
|
source "drivers/net/ethernet/pensando/Kconfig"
|
||||||
|
source "drivers/net/ethernet/qlogic/Kconfig"
|
||||||
|
source "drivers/net/ethernet/qualcomm/Kconfig"
|
||||||
|
+source "drivers/net/ethernet/ralink/Kconfig"
|
||||||
|
source "drivers/net/ethernet/rdc/Kconfig"
|
||||||
|
source "drivers/net/ethernet/realtek/Kconfig"
|
||||||
|
source "drivers/net/ethernet/renesas/Kconfig"
|
||||||
|
--- a/drivers/net/ethernet/Makefile
|
||||||
|
+++ b/drivers/net/ethernet/Makefile
|
||||||
|
@@ -72,6 +72,7 @@ obj-$(CONFIG_NET_VENDOR_PACKET_ENGINES)
|
||||||
|
obj-$(CONFIG_NET_VENDOR_PASEMI) += pasemi/
|
||||||
|
obj-$(CONFIG_NET_VENDOR_QLOGIC) += qlogic/
|
||||||
|
obj-$(CONFIG_NET_VENDOR_QUALCOMM) += qualcomm/
|
||||||
|
+obj-$(CONFIG_NET_VENDOR_RALINK) += ralink/
|
||||||
|
obj-$(CONFIG_NET_VENDOR_REALTEK) += realtek/
|
||||||
|
obj-$(CONFIG_NET_VENDOR_RENESAS) += renesas/
|
||||||
|
obj-$(CONFIG_NET_VENDOR_RDC) += rdc/
|
@ -0,0 +1,19 @@
|
|||||||
|
--- a/arch/mips/include/asm/mach-ralink/mt7620.h
|
||||||
|
+++ b/arch/mips/include/asm/mach-ralink/mt7620.h
|
||||||
|
@@ -135,4 +135,16 @@ static inline int mt7620_get_eco(void)
|
||||||
|
return rt_sysc_r32(SYSC_REG_CHIP_REV) & CHIP_REV_ECO_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static inline int mt7620_get_chipver(void)
|
||||||
|
+{
|
||||||
|
+ return (rt_sysc_r32(SYSC_REG_CHIP_REV) >> CHIP_REV_VER_SHIFT) &
|
||||||
|
+ CHIP_REV_VER_MASK;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline int mt7620_get_pkg(void)
|
||||||
|
+{
|
||||||
|
+ return (rt_sysc_r32(SYSC_REG_CHIP_REV) >> CHIP_REV_PKG_SHIFT) &
|
||||||
|
+ CHIP_REV_PKG_MASK;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
#endif
|
@ -0,0 +1,89 @@
|
|||||||
|
From f798b7588bd7397bbab958281ca6c88d08714941 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Date: Thu, 12 Mar 2020 12:29:15 +0100
|
||||||
|
Subject: [PATCH] MIPS: ralink: mt7621: introduce 'soc_device' initialization
|
||||||
|
|
||||||
|
mt7621 SoC has its own 'ralink_soc_info' structure with some
|
||||||
|
information about the soc itself. Pcie controller and pcie phy
|
||||||
|
drivers for this soc which are still in staging git tree make uses
|
||||||
|
of 'soc_device_attribute' looking for revision 'E2' in order to
|
||||||
|
know if reset lines are or not inverted. This way of doing things
|
||||||
|
seems to be necessary in order to make things clean and properly.
|
||||||
|
Hence, introduce this 'soc_device' to be able to properly use those
|
||||||
|
attributes in drivers. Also set 'data' pointer points to the struct
|
||||||
|
'ralink_soc_info' to be able to export also current soc information
|
||||||
|
using this mechanism.
|
||||||
|
|
||||||
|
Cc: Paul Burton <paul.burton@mips.com>
|
||||||
|
Cc: ralf@linux-mips.org
|
||||||
|
Cc: jhogan@kernel.org
|
||||||
|
Cc: john@phrozen.org
|
||||||
|
Cc: NeilBrown <neil@brown.name>
|
||||||
|
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||||
|
Cc: linux-mips@vger.kernel.org
|
||||||
|
|
||||||
|
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||||||
|
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
|
||||||
|
---
|
||||||
|
arch/mips/ralink/mt7621.c | 32 +++++++++++++++++++++++++++++++-
|
||||||
|
1 file changed, 31 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
--- a/arch/mips/ralink/mt7621.c
|
||||||
|
+++ b/arch/mips/ralink/mt7621.c
|
||||||
|
@@ -7,6 +7,8 @@
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
+#include <linux/slab.h>
|
||||||
|
+#include <linux/sys_soc.h>
|
||||||
|
#include <linux/jiffies.h>
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/clkdev.h>
|
||||||
|
@@ -294,6 +296,33 @@ static int udelay_recal(void)
|
||||||
|
}
|
||||||
|
device_initcall(udelay_recal);
|
||||||
|
|
||||||
|
+static void soc_dev_init(struct ralink_soc_info *soc_info, u32 rev)
|
||||||
|
+{
|
||||||
|
+ struct soc_device *soc_dev;
|
||||||
|
+ struct soc_device_attribute *soc_dev_attr;
|
||||||
|
+
|
||||||
|
+ soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
|
||||||
|
+ if (!soc_dev_attr)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ soc_dev_attr->soc_id = "mt7621";
|
||||||
|
+ soc_dev_attr->family = "Ralink";
|
||||||
|
+
|
||||||
|
+ if (((rev >> CHIP_REV_VER_SHIFT) & CHIP_REV_VER_MASK) == 1 &&
|
||||||
|
+ (rev & CHIP_REV_ECO_MASK) == 1)
|
||||||
|
+ soc_dev_attr->revision = "E2";
|
||||||
|
+ else
|
||||||
|
+ soc_dev_attr->revision = "E1";
|
||||||
|
+
|
||||||
|
+ soc_dev_attr->data = soc_info;
|
||||||
|
+
|
||||||
|
+ soc_dev = soc_device_register(soc_dev_attr);
|
||||||
|
+ if (IS_ERR(soc_dev)) {
|
||||||
|
+ kfree(soc_dev_attr);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void prom_soc_init(struct ralink_soc_info *soc_info)
|
||||||
|
{
|
||||||
|
void __iomem *sysc = (void __iomem *) KSEG1ADDR(MT7621_SYSC_BASE);
|
||||||
|
@@ -345,11 +374,12 @@ void prom_soc_init(struct ralink_soc_inf
|
||||||
|
soc_info->mem_detect = mt7621_memory_detect;
|
||||||
|
rt2880_pinmux_data = mt7621_pinmux_data;
|
||||||
|
|
||||||
|
-
|
||||||
|
if (!register_cps_smp_ops())
|
||||||
|
return;
|
||||||
|
if (!register_cmp_smp_ops())
|
||||||
|
return;
|
||||||
|
if (!register_vsmp_smp_ops())
|
||||||
|
return;
|
||||||
|
+
|
||||||
|
+ soc_dev_init(soc_info, rev);
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
--- a/drivers/mtd/spi-nor/spi-nor.c
|
||||||
|
+++ b/drivers/mtd/spi-nor/spi-nor.c
|
||||||
|
@@ -2303,6 +2303,11 @@ static const struct flash_info spi_nor_i
|
||||||
|
SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
|
||||||
|
.fixups = &gd25q256_fixups,
|
||||||
|
},
|
||||||
|
+ {
|
||||||
|
+ "gd25q512", INFO(0xc84020, 0, 64 * 1024, 1024,
|
||||||
|
+ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
|
||||||
|
+ SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4B_OPCODES)
|
||||||
|
+ },
|
||||||
|
|
||||||
|
/* Intel/Numonyx -- xxxs33b */
|
||||||
|
{ "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) },
|
@ -0,0 +1,34 @@
|
|||||||
|
From bd0f89de5476ca25e73fae829ba3e1dafae1d90d Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= <opensource@vdorst.com>
|
||||||
|
Date: Fri, 21 Jun 2019 10:04:05 +0200
|
||||||
|
Subject: [PATCH] net: ethernet: mediatek: support net-labels
|
||||||
|
|
||||||
|
With this patch, device name can be set within dts file in the same way as dsa
|
||||||
|
port can.
|
||||||
|
Add: label = "wan"; to GMAC node.
|
||||||
|
|
||||||
|
Signed-off-by: René van Dorst <opensource@vdorst.com>
|
||||||
|
---
|
||||||
|
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++++
|
||||||
|
1 file changed, 4 insertions(+)
|
||||||
|
|
||||||
|
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||||
|
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||||
|
@@ -2922,6 +2922,7 @@ static const struct net_device_ops mtk_n
|
||||||
|
|
||||||
|
static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
|
||||||
|
{
|
||||||
|
+ const char *name = of_get_property(np, "label", NULL);
|
||||||
|
const __be32 *_id = of_get_property(np, "reg", NULL);
|
||||||
|
struct phylink *phylink;
|
||||||
|
int phy_mode, id, err;
|
||||||
|
@@ -3014,6 +3015,9 @@ static int mtk_add_mac(struct mtk_eth *e
|
||||||
|
|
||||||
|
eth->netdev[id]->max_mtu = MTK_MAX_RX_LENGTH - MTK_RX_ETH_HLEN;
|
||||||
|
|
||||||
|
+ if (name)
|
||||||
|
+ strlcpy(eth->netdev[id]->name, name, IFNAMSIZ);
|
||||||
|
+
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
free_netdev:
|
@ -0,0 +1,47 @@
|
|||||||
|
From 0b6eb1e68290243d439ee330ea8d0b239a5aec69 Mon Sep 17 00:00:00 2001
|
||||||
|
From: John Crispin <blogic@openwrt.org>
|
||||||
|
Date: Sun, 27 Jul 2014 09:38:50 +0100
|
||||||
|
Subject: [PATCH 34/53] NET: multi phy support
|
||||||
|
|
||||||
|
Signed-off-by: John Crispin <blogic@openwrt.org>
|
||||||
|
---
|
||||||
|
drivers/net/phy/phy.c | 9 ++++++---
|
||||||
|
include/linux/phy.h | 1 +
|
||||||
|
2 files changed, 7 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/phy/phy.c
|
||||||
|
+++ b/drivers/net/phy/phy.c
|
||||||
|
@@ -546,7 +546,10 @@ static int phy_check_link_status(struct
|
||||||
|
phy_link_up(phydev);
|
||||||
|
} else if (!phydev->link && phydev->state != PHY_NOLINK) {
|
||||||
|
phydev->state = PHY_NOLINK;
|
||||||
|
- phy_link_down(phydev, true);
|
||||||
|
+ if (!phydev->no_auto_carrier_off)
|
||||||
|
+ phy_link_down(phydev, true);
|
||||||
|
+ else
|
||||||
|
+ phy_link_down(phydev, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
@@ -926,7 +929,10 @@ void phy_state_machine(struct work_struc
|
||||||
|
case PHY_HALTED:
|
||||||
|
if (phydev->link) {
|
||||||
|
phydev->link = 0;
|
||||||
|
- phy_link_down(phydev, true);
|
||||||
|
+ if (!phydev->no_auto_carrier_off)
|
||||||
|
+ phy_link_down(phydev, true);
|
||||||
|
+ else
|
||||||
|
+ phy_link_down(phydev, false);
|
||||||
|
}
|
||||||
|
do_suspend = true;
|
||||||
|
break;
|
||||||
|
--- a/include/linux/phy.h
|
||||||
|
+++ b/include/linux/phy.h
|
||||||
|
@@ -380,6 +380,7 @@ struct phy_device {
|
||||||
|
unsigned suspended_by_mdio_bus:1;
|
||||||
|
unsigned sysfs_links:1;
|
||||||
|
unsigned loopback_enabled:1;
|
||||||
|
+ unsigned no_auto_carrier_off:1;
|
||||||
|
|
||||||
|
unsigned autoneg:1;
|
||||||
|
/* The most recently read link state */
|
156
target/linux/ramips/patches-5.10/991-at803x.patch
Normal file
156
target/linux/ramips/patches-5.10/991-at803x.patch
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
From 924453aa9d2324e5611f8e2b71df746d8f0c79f1 Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Ren=C3=A9=20van=20Dorst?= <opensource@vdorst.com>
|
||||||
|
Date: Fri, 13 Nov 2020 16:11:32 +0100
|
||||||
|
Subject: [PATCH] net: phy: at803x: add support for SFP module in
|
||||||
|
RGMII-to-x-base mode
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
Signed-off-by: René van Dorst <opensource@vdorst.com>
|
||||||
|
---
|
||||||
|
drivers/net/phy/at803x.c | 91 ++++++++++++++++++++++++++++++++++++++++
|
||||||
|
1 file changed, 91 insertions(+)
|
||||||
|
|
||||||
|
--- a/drivers/net/phy/at803x.c
|
||||||
|
+++ b/drivers/net/phy/at803x.c
|
||||||
|
@@ -14,6 +14,8 @@
|
||||||
|
#include <linux/etherdevice.h>
|
||||||
|
#include <linux/of_gpio.h>
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
|
+#include <linux/sfp.h>
|
||||||
|
+#include <linux/phylink.h>
|
||||||
|
|
||||||
|
#define AT803X_SPECIFIC_STATUS 0x11
|
||||||
|
#define AT803X_SS_SPEED_MASK (3 << 14)
|
||||||
|
@@ -53,9 +55,18 @@
|
||||||
|
|
||||||
|
#define AT803X_MODE_CFG_MASK 0x0F
|
||||||
|
#define AT803X_MODE_CFG_SGMII 0x01
|
||||||
|
+#define AT803X_MODE_CFG_BX1000_RGMII_50 0x02
|
||||||
|
+#define AT803X_MODE_CFG_BX1000_RGMII_75 0x03
|
||||||
|
+#define AT803X_MODE_FIBER 0x01
|
||||||
|
+#define AT803X_MODE_COPPER 0x00
|
||||||
|
|
||||||
|
#define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/
|
||||||
|
#define AT803X_PSSR_MR_AN_COMPLETE 0x0200
|
||||||
|
+#define PSSR_LINK BIT(10)
|
||||||
|
+#define PSSR_SYNC_STATUS BIT(8)
|
||||||
|
+#define PSSR_DUPLEX BIT(13)
|
||||||
|
+#define PSSR_SPEED_1000 BIT(15)
|
||||||
|
+#define PSSR_SPEED_100 BIT(14)
|
||||||
|
|
||||||
|
#define AT803X_DEBUG_REG_0 0x00
|
||||||
|
#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15)
|
||||||
|
@@ -243,10 +254,72 @@ static int at803x_resume(struct phy_devi
|
||||||
|
return phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int at803x_mode(struct phy_device *phydev)
|
||||||
|
+{
|
||||||
|
+ int mode;
|
||||||
|
+
|
||||||
|
+ mode = phy_read(phydev, AT803X_REG_CHIP_CONFIG) & AT803X_MODE_CFG_MASK;
|
||||||
|
+
|
||||||
|
+ if (mode == AT803X_MODE_CFG_BX1000_RGMII_50 ||
|
||||||
|
+ mode == AT803X_MODE_CFG_BX1000_RGMII_75)
|
||||||
|
+ return AT803X_MODE_FIBER;
|
||||||
|
+ return AT803X_MODE_COPPER;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int at803x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
|
||||||
|
+{
|
||||||
|
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(at803x_support) = { 0, };
|
||||||
|
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
|
||||||
|
+ struct phy_device *phydev = upstream;
|
||||||
|
+ phy_interface_t iface;
|
||||||
|
+
|
||||||
|
+ phylink_set(at803x_support, 1000baseX_Full);
|
||||||
|
+ /* AT803x only support 1000baseX but SGMII works fine when module runs
|
||||||
|
+ * at 1Gbit.
|
||||||
|
+ */
|
||||||
|
+ phylink_set(at803x_support, 1000baseT_Full);
|
||||||
|
+
|
||||||
|
+ sfp_parse_support(phydev->sfp_bus, id, support);
|
||||||
|
+
|
||||||
|
+ // Limit to interfaces that both sides support
|
||||||
|
+ linkmode_and(support, support, at803x_support);
|
||||||
|
+
|
||||||
|
+ if (linkmode_empty(support))
|
||||||
|
+ goto unsupported_mode;
|
||||||
|
+
|
||||||
|
+ iface = sfp_select_interface(phydev->sfp_bus, support);
|
||||||
|
+
|
||||||
|
+ if (iface != PHY_INTERFACE_MODE_SGMII &&
|
||||||
|
+ iface != PHY_INTERFACE_MODE_1000BASEX)
|
||||||
|
+ goto unsupported_mode;
|
||||||
|
+
|
||||||
|
+ dev_info(&phydev->mdio.dev, "SFP interface %s", phy_modes(iface));
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+unsupported_mode:
|
||||||
|
+ dev_info(&phydev->mdio.dev, "incompatible SFP module inserted;"
|
||||||
|
+ "Only SGMII at 1Gbit/1000BASEX are supported!\n");
|
||||||
|
+ return -EINVAL;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static const struct sfp_upstream_ops at803x_sfp_ops = {
|
||||||
|
+ .attach = phy_sfp_attach,
|
||||||
|
+ .detach = phy_sfp_detach,
|
||||||
|
+ .module_insert = at803x_sfp_insert,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
static int at803x_probe(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
struct device *dev = &phydev->mdio.dev;
|
||||||
|
struct at803x_priv *priv;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ if (at803x_mode(phydev) == AT803X_MODE_FIBER) {
|
||||||
|
+ ret = phy_sfp_probe(phydev, &at803x_sfp_ops);
|
||||||
|
+ if (ret < 0)
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||||
|
if (!priv)
|
||||||
|
@@ -394,6 +467,10 @@ static int at803x_read_status(struct phy
|
||||||
|
{
|
||||||
|
int ss, err, old_link = phydev->link;
|
||||||
|
|
||||||
|
+ /* Handle (Fiber) SGMII to RGMII mode */
|
||||||
|
+ if (at803x_mode(phydev) == AT803X_MODE_FIBER)
|
||||||
|
+ return genphy_c37_read_status(phydev);
|
||||||
|
+
|
||||||
|
/* Update the link, but return if there was an error */
|
||||||
|
err = genphy_update_link(phydev);
|
||||||
|
if (err)
|
||||||
|
@@ -448,6 +525,19 @@ static int at803x_read_status(struct phy
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int at803x_config_aneg(struct phy_device *phydev)
|
||||||
|
+{
|
||||||
|
+ /* Handle (Fiber) SerDes to RGMII mode */
|
||||||
|
+ if (at803x_mode(phydev) == AT803X_MODE_FIBER) {
|
||||||
|
+ pr_warn("%s: fiber\n", __func__);
|
||||||
|
+ return genphy_c37_config_aneg(phydev);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ pr_warn("%s: enter\n", __func__);
|
||||||
|
+
|
||||||
|
+ return genphy_config_aneg(phydev);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static struct phy_driver at803x_driver[] = {
|
||||||
|
{
|
||||||
|
/* ATHEROS 8035 */
|
||||||
|
@@ -491,6 +581,7 @@ static struct phy_driver at803x_driver[]
|
||||||
|
.suspend = at803x_suspend,
|
||||||
|
.resume = at803x_resume,
|
||||||
|
/* PHY_GBIT_FEATURES */
|
||||||
|
+ .config_aneg = at803x_config_aneg,
|
||||||
|
.read_status = at803x_read_status,
|
||||||
|
.aneg_done = at803x_aneg_done,
|
||||||
|
.ack_interrupt = &at803x_ack_interrupt,
|
@ -0,0 +1,21 @@
|
|||||||
|
--- a/arch/mips/pci/pci-mt7620.c
|
||||||
|
+++ b/arch/mips/pci/pci-mt7620.c
|
||||||
|
@@ -32,6 +32,7 @@
|
||||||
|
#define PPLL_CFG1 0x9c
|
||||||
|
|
||||||
|
#define PPLL_DRV 0xa0
|
||||||
|
+#define PPLL_LD BIT(23)
|
||||||
|
#define PDRV_SW_SET BIT(31)
|
||||||
|
#define LC_CKDRVPD BIT(19)
|
||||||
|
#define LC_CKDRVOHZ BIT(18)
|
||||||
|
@@ -239,8 +240,8 @@ static int mt7620_pci_hw_init(struct pla
|
||||||
|
rt_sysc_m32(0, RALINK_PCIE0_CLK_EN, RALINK_CLKCFG1);
|
||||||
|
mdelay(100);
|
||||||
|
|
||||||
|
- if (!(rt_sysc_r32(PPLL_CFG1) & PDRV_SW_SET)) {
|
||||||
|
- dev_err(&pdev->dev, "MT7620 PPLL unlock\n");
|
||||||
|
+ if (!(rt_sysc_r32(PPLL_CFG1) & PPLL_LD)) {
|
||||||
|
+ dev_err(&pdev->dev, "MT7620 PPLL is unlocked, aborting init\n");
|
||||||
|
reset_control_assert(rstpcie0);
|
||||||
|
rt_sysc_m32(RALINK_PCIE0_CLK_EN, 0, RALINK_CLKCFG1);
|
||||||
|
return -1;
|
Loading…
Reference in New Issue
Block a user