mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-13 16:37:30 +00:00
Merge branch 'master' of git://git.denx.de/u-boot-mips
This commit is contained in:
commit
d2427caf54
57 changed files with 3705 additions and 96 deletions
|
@ -23,6 +23,7 @@ config TARGET_QEMU_MIPS
|
|||
|
||||
config TARGET_MALTA
|
||||
bool "Support malta"
|
||||
select DYNAMIC_IO_PORT_BASE
|
||||
select SUPPORTS_BIG_ENDIAN
|
||||
select SUPPORTS_LITTLE_ENDIAN
|
||||
select SUPPORTS_CPU_MIPS32_R1
|
||||
|
@ -54,6 +55,11 @@ config TARGET_PB1X00
|
|||
select SYS_MIPS_CACHE_INIT_RAM_LOAD
|
||||
select MIPS_TUNE_4KC
|
||||
|
||||
config MACH_PIC32
|
||||
bool "Support Microchip PIC32"
|
||||
select OF_CONTROL
|
||||
select DM
|
||||
|
||||
endchoice
|
||||
|
||||
source "board/dbau1x00/Kconfig"
|
||||
|
@ -61,6 +67,7 @@ source "board/imgtec/malta/Kconfig"
|
|||
source "board/micronas/vct/Kconfig"
|
||||
source "board/pb1x00/Kconfig"
|
||||
source "board/qemu-mips/Kconfig"
|
||||
source "arch/mips/mach-pic32/Kconfig"
|
||||
|
||||
if MIPS
|
||||
|
||||
|
@ -217,6 +224,9 @@ config MIPS_L1_CACHE_SHIFT
|
|||
default "4" if MIPS_L1_CACHE_SHIFT_4
|
||||
default "5"
|
||||
|
||||
config DYNAMIC_IO_PORT_BASE
|
||||
bool
|
||||
|
||||
endif
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -8,6 +8,7 @@ libs-y += arch/mips/cpu/
|
|||
libs-y += arch/mips/lib/
|
||||
|
||||
machine-$(CONFIG_SOC_AU1X00) += au1x00
|
||||
machine-$(CONFIG_MACH_PIC32) += pic32
|
||||
|
||||
machdirs := $(patsubst %,arch/mips/mach-%/,$(machine-y))
|
||||
libs-y += $(machdirs)
|
||||
|
|
|
@ -115,7 +115,7 @@ reset:
|
|||
|
||||
/* Clear watch registers */
|
||||
MTC0 zero, CP0_WATCHLO
|
||||
MTC0 zero, CP0_WATCHHI
|
||||
mtc0 zero, CP0_WATCHHI
|
||||
|
||||
/* WP(Watch Pending), SW0/1 should be cleared */
|
||||
mtc0 zero, CP0_CAUSE
|
||||
|
@ -161,14 +161,14 @@ reset:
|
|||
#endif
|
||||
|
||||
/* Set up temporary stack */
|
||||
PTR_LI t0, -16
|
||||
li t0, -16
|
||||
PTR_LI t1, CONFIG_SYS_INIT_SP_ADDR
|
||||
and sp, t1, t0 # force 16 byte alignment
|
||||
PTR_SUB sp, sp, GD_SIZE # reserve space for gd
|
||||
and sp, sp, t0 # force 16 byte alignment
|
||||
move k0, sp # save gd pointer
|
||||
#ifdef CONFIG_SYS_MALLOC_F_LEN
|
||||
PTR_LI t2, CONFIG_SYS_MALLOC_F_LEN
|
||||
li t2, CONFIG_SYS_MALLOC_F_LEN
|
||||
PTR_SUB sp, sp, t2 # reserve space for early malloc
|
||||
and sp, sp, t0 # force 16 byte alignment
|
||||
#endif
|
||||
|
@ -177,15 +177,15 @@ reset:
|
|||
/* Clear gd */
|
||||
move t0, k0
|
||||
1:
|
||||
sw zero, 0(t0)
|
||||
PTR_S zero, 0(t0)
|
||||
blt t0, t1, 1b
|
||||
PTR_ADDI t0, 4
|
||||
PTR_ADDI t0, PTRSIZE
|
||||
|
||||
#ifdef CONFIG_SYS_MALLOC_F_LEN
|
||||
PTR_ADDU t0, k0, GD_MALLOC_BASE # gd->malloc_base offset
|
||||
sw sp, 0(t0)
|
||||
PTR_S sp, GD_MALLOC_BASE(k0) # gd->malloc_base offset
|
||||
#endif
|
||||
|
||||
move a0, zero # a0 <-- boot_flags = 0
|
||||
PTR_LA t9, board_init_f
|
||||
jr t9
|
||||
move ra, zero
|
||||
|
@ -224,11 +224,11 @@ ENTRY(relocate_code)
|
|||
* t2 = source end address
|
||||
*/
|
||||
1:
|
||||
lw t3, 0(t0)
|
||||
sw t3, 0(t1)
|
||||
PTR_ADDU t0, 4
|
||||
PTR_L t3, 0(t0)
|
||||
PTR_S t3, 0(t1)
|
||||
PTR_ADDU t0, PTRSIZE
|
||||
blt t0, t2, 1b
|
||||
PTR_ADDU t1, 4
|
||||
PTR_ADDU t1, PTRSIZE
|
||||
|
||||
/* If caches were enabled, we would have to flush them here. */
|
||||
PTR_SUB a1, t1, s2 # a1 <-- size
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
dtb-y +=
|
||||
dtb-$(CONFIG_TARGET_PIC32MZDASK) += pic32mzda_sk.dtb
|
||||
|
||||
targets += $(dtb-y)
|
||||
|
||||
|
|
174
arch/mips/dts/pic32mzda.dtsi
Normal file
174
arch/mips/dts/pic32mzda.dtsi
Normal file
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* Copyright 2015 Microchip Technology, Inc.
|
||||
* Purna Chandra Mandal, <purna.mandal@microchip.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/clock/microchip,clock.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include "skeleton.dtsi"
|
||||
|
||||
/ {
|
||||
compatible = "microchip,pic32mzda", "microchip,pic32mz";
|
||||
|
||||
aliases {
|
||||
gpio0 = &gpioA;
|
||||
gpio1 = &gpioB;
|
||||
gpio2 = &gpioC;
|
||||
gpio3 = &gpioD;
|
||||
gpio4 = &gpioE;
|
||||
gpio5 = &gpioF;
|
||||
gpio6 = &gpioG;
|
||||
gpio7 = &gpioH;
|
||||
gpio8 = &gpioJ;
|
||||
gpio9 = &gpioK;
|
||||
};
|
||||
|
||||
cpus {
|
||||
cpu@0 {
|
||||
compatible = "mips,mips14kc";
|
||||
};
|
||||
};
|
||||
|
||||
clock: clk@1f801200 {
|
||||
compatible = "microchip,pic32mzda-clk";
|
||||
reg = <0x1f801200 0x1000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
uart1: serial@1f822000 {
|
||||
compatible = "microchip,pic32mzda-uart";
|
||||
reg = <0x1f822000 0x50>;
|
||||
interrupts = <112 IRQ_TYPE_LEVEL_HIGH>;
|
||||
status = "disabled";
|
||||
clocks = <&clock PB2CLK>;
|
||||
};
|
||||
|
||||
uart2: serial@1f822200 {
|
||||
compatible = "microchip,pic32mzda-uart";
|
||||
reg = <0x1f822200 0x50>;
|
||||
interrupts = <145 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clock PB2CLK>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
uart6: serial@1f822a00 {
|
||||
compatible = "microchip,pic32mzda-uart";
|
||||
reg = <0x1f822a00 0x50>;
|
||||
interrupts = <188 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clock PB2CLK>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
evic: interrupt-controller@1f810000 {
|
||||
compatible = "microchip,pic32mzda-evic";
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
reg = <0x1f810000 0x1000>;
|
||||
};
|
||||
|
||||
pinctrl: pinctrl@1f801400 {
|
||||
compatible = "microchip,pic32mzda-pinctrl";
|
||||
reg = <0x1f801400 0x100>, /* in */
|
||||
<0x1f801500 0x200>, /* out */
|
||||
<0x1f860000 0xa00>; /* port */
|
||||
reg-names = "ppsin","ppsout","port";
|
||||
status = "disabled";
|
||||
|
||||
ranges = <0 0x1f860000 0xa00>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
gpioA: gpio0@0 {
|
||||
compatible = "microchip,pic32mzda-gpio";
|
||||
reg = <0x000 0x48>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
||||
gpioB: gpio1@100 {
|
||||
compatible = "microchip,pic32mzda-gpio";
|
||||
reg = <0x100 0x48>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
||||
gpioC: gpio2@200 {
|
||||
compatible = "microchip,pic32mzda-gpio";
|
||||
reg = <0x200 0x48>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
||||
gpioD: gpio3@300 {
|
||||
compatible = "microchip,pic32mzda-gpio";
|
||||
reg = <0x300 0x48>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
||||
gpioE: gpio4@400 {
|
||||
compatible = "microchip,pic32mzda-gpio";
|
||||
reg = <0x400 0x48>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
||||
gpioF: gpio5@500 {
|
||||
compatible = "microchip,pic32mzda-gpio";
|
||||
reg = <0x500 0x48>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
||||
gpioG: gpio6@600 {
|
||||
compatible = "microchip,pic32mzda-gpio";
|
||||
reg = <0x600 0x48>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
||||
gpioH: gpio7@700 {
|
||||
compatible = "microchip,pic32mzda-gpio";
|
||||
reg = <0x700 0x48>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
||||
gpioJ: gpio8@800 {
|
||||
compatible = "microchip,pic32mzda-gpio";
|
||||
reg = <0x800 0x48>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
||||
gpioK: gpio9@900 {
|
||||
compatible = "microchip,pic32mzda-gpio";
|
||||
reg = <0x900 0x48>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
};
|
||||
|
||||
sdhci: sdhci@1f8ec000 {
|
||||
compatible = "microchip,pic32mzda-sdhci";
|
||||
reg = <0x1f8ec000 0x100>;
|
||||
interrupts = <191 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clock REF4CLK>, <&clock PB5CLK>;
|
||||
clock-names = "base_clk", "sys_clk";
|
||||
clock-freq-min-max = <25000000>,<25000000>;
|
||||
bus-width = <4>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
ethernet: ethernet@1f882000 {
|
||||
compatible = "microchip,pic32mzda-eth";
|
||||
reg = <0x1f882000 0x1000>;
|
||||
interrupts = <153 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clock PB5CLK>;
|
||||
status = "disabled";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
};
|
55
arch/mips/dts/pic32mzda_sk.dts
Normal file
55
arch/mips/dts/pic32mzda_sk.dts
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Purna Chandra Mandal, purna.mandal@microchip.com
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include "pic32mzda.dtsi"
|
||||
|
||||
/ {
|
||||
model = "Microchip PIC32MZDASK";
|
||||
compatible = "microchip,pic32mzdask", "microchip,pic32mzda";
|
||||
|
||||
aliases {
|
||||
console = &uart2;
|
||||
serial0 = &uart2;
|
||||
};
|
||||
|
||||
chosen {
|
||||
stdout-path = "serial0:115200n8";
|
||||
};
|
||||
};
|
||||
|
||||
&clock {
|
||||
microchip,refo2-frequency = <50000000>;
|
||||
microchip,refo4-frequency = <25000000>;
|
||||
microchip,refo5-frequency = <40000000>;
|
||||
status = "okay";
|
||||
u-boot,dm-pre-reloc;
|
||||
};
|
||||
|
||||
&pinctrl {
|
||||
status = "okay";
|
||||
u-boot,dm-pre-reloc;
|
||||
};
|
||||
|
||||
&uart2 {
|
||||
status = "okay";
|
||||
u-boot,dm-pre-reloc;
|
||||
};
|
||||
|
||||
&sdhci {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
ðernet {
|
||||
reset-gpios = <&gpioJ 15 0>;
|
||||
status = "okay";
|
||||
phy-mode = "rmii";
|
||||
phy-handle = <ðernet_phy>;
|
||||
ethernet_phy: lan8740_phy@0 {
|
||||
reg = <0>;
|
||||
};
|
||||
};
|
|
@ -12,6 +12,9 @@
|
|||
|
||||
/* Architecture-specific global data */
|
||||
struct arch_global_data {
|
||||
#ifdef CONFIG_DYNAMIC_IO_PORT_BASE
|
||||
unsigned long io_port_base;
|
||||
#endif
|
||||
#ifdef CONFIG_JZSOC
|
||||
/* There are other clocks in the jz4740 */
|
||||
unsigned long per_clk; /* Peripheral bus clock */
|
||||
|
|
|
@ -25,11 +25,6 @@
|
|||
#include <mangle-port.h>
|
||||
#include <spaces.h>
|
||||
|
||||
/*
|
||||
* Slowdown I/O port space accesses for antique hardware.
|
||||
*/
|
||||
#undef CONF_SLOWDOWN_IO
|
||||
|
||||
/*
|
||||
* Raw operations are never swapped in software. OTOH values that raw
|
||||
* operations are working on may or may not have been swapped by the bus
|
||||
|
@ -46,57 +41,36 @@
|
|||
|
||||
#define IO_SPACE_LIMIT 0xffff
|
||||
|
||||
/*
|
||||
* On MIPS I/O ports are memory mapped, so we access them using normal
|
||||
* load/store instructions. mips_io_port_base is the virtual address to
|
||||
* which all ports are being mapped. For sake of efficiency some code
|
||||
* assumes that this is an address that can be loaded with a single lui
|
||||
* instruction, so the lower 16 bits must be zero. Should be true on
|
||||
* on any sane architecture; generic code does not use this assumption.
|
||||
*/
|
||||
extern const unsigned long mips_io_port_base;
|
||||
#ifdef CONFIG_DYNAMIC_IO_PORT_BASE
|
||||
|
||||
static inline ulong mips_io_port_base(void)
|
||||
{
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
return gd->arch.io_port_base;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gcc will generate code to load the value of mips_io_port_base after each
|
||||
* function call which may be fairly wasteful in some cases. So we don't
|
||||
* play quite by the book. We tell gcc mips_io_port_base is a long variable
|
||||
* which solves the code generation issue. Now we need to violate the
|
||||
* aliasing rules a little to make initialization possible and finally we
|
||||
* will need the barrier() to fight side effects of the aliasing chat.
|
||||
* This trickery will eventually collapse under gcc's optimizer. Oh well.
|
||||
*/
|
||||
static inline void set_io_port_base(unsigned long base)
|
||||
{
|
||||
* (unsigned long *) &mips_io_port_base = base;
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
gd->arch.io_port_base = base;
|
||||
barrier();
|
||||
}
|
||||
|
||||
/*
|
||||
* Thanks to James van Artsdalen for a better timing-fix than
|
||||
* the two short jumps: using outb's to a nonexistent port seems
|
||||
* to guarantee better timings even on fast machines.
|
||||
*
|
||||
* On the other hand, I'd like to be sure of a non-existent port:
|
||||
* I feel a bit unsafe about using 0x80 (should be safe, though)
|
||||
*
|
||||
* Linus
|
||||
*
|
||||
*/
|
||||
#else /* !CONFIG_DYNAMIC_IO_PORT_BASE */
|
||||
|
||||
#define __SLOW_DOWN_IO \
|
||||
__asm__ __volatile__( \
|
||||
"sb\t$0,0x80(%0)" \
|
||||
: : "r" (mips_io_port_base));
|
||||
static inline ulong mips_io_port_base(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONF_SLOWDOWN_IO
|
||||
#ifdef REALLY_SLOW_IO
|
||||
#define SLOW_DOWN_IO { __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; }
|
||||
#else
|
||||
#define SLOW_DOWN_IO __SLOW_DOWN_IO
|
||||
#endif
|
||||
#else
|
||||
#define SLOW_DOWN_IO
|
||||
#endif
|
||||
static inline void set_io_port_base(unsigned long base)
|
||||
{
|
||||
BUG_ON(base);
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_DYNAMIC_IO_PORT_BASE */
|
||||
|
||||
/*
|
||||
* virt_to_phys - map virtual addresses to physical
|
||||
|
@ -316,7 +290,7 @@ static inline type pfx##read##bwlq(const volatile void __iomem *mem) \
|
|||
return pfx##ioswab##bwlq(__mem, __val); \
|
||||
}
|
||||
|
||||
#define __BUILD_IOPORT_SINGLE(pfx, bwlq, type, p, slow) \
|
||||
#define __BUILD_IOPORT_SINGLE(pfx, bwlq, type, p) \
|
||||
\
|
||||
static inline void pfx##out##bwlq##p(type val, unsigned long port) \
|
||||
{ \
|
||||
|
@ -325,7 +299,7 @@ static inline void pfx##out##bwlq##p(type val, unsigned long port) \
|
|||
\
|
||||
war_octeon_io_reorder_wmb(); \
|
||||
\
|
||||
__addr = (void *)__swizzle_addr_##bwlq(mips_io_port_base + port); \
|
||||
__addr = (void *)__swizzle_addr_##bwlq(mips_io_port_base() + port); \
|
||||
\
|
||||
__val = pfx##ioswab##bwlq(__addr, val); \
|
||||
\
|
||||
|
@ -333,7 +307,6 @@ static inline void pfx##out##bwlq##p(type val, unsigned long port) \
|
|||
BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long)); \
|
||||
\
|
||||
*__addr = __val; \
|
||||
slow; \
|
||||
} \
|
||||
\
|
||||
static inline type pfx##in##bwlq##p(unsigned long port) \
|
||||
|
@ -341,12 +314,11 @@ static inline type pfx##in##bwlq##p(unsigned long port) \
|
|||
volatile type *__addr; \
|
||||
type __val; \
|
||||
\
|
||||
__addr = (void *)__swizzle_addr_##bwlq(mips_io_port_base + port); \
|
||||
__addr = (void *)__swizzle_addr_##bwlq(mips_io_port_base() + port); \
|
||||
\
|
||||
BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long)); \
|
||||
\
|
||||
__val = *__addr; \
|
||||
slow; \
|
||||
\
|
||||
return pfx##ioswab##bwlq(__addr, __val); \
|
||||
}
|
||||
|
@ -367,8 +339,8 @@ BUILDIO_MEM(l, u32)
|
|||
BUILDIO_MEM(q, u64)
|
||||
|
||||
#define __BUILD_IOPORT_PFX(bus, bwlq, type) \
|
||||
__BUILD_IOPORT_SINGLE(bus, bwlq, type, ,) \
|
||||
__BUILD_IOPORT_SINGLE(bus, bwlq, type, _p, SLOW_DOWN_IO)
|
||||
__BUILD_IOPORT_SINGLE(bus, bwlq, type, ) \
|
||||
__BUILD_IOPORT_SINGLE(bus, bwlq, type, _p)
|
||||
|
||||
#define BUILDIO_IOPORT(bwlq, type) \
|
||||
__BUILD_IOPORT_PFX(, bwlq, type) \
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
obj-y += cache.o
|
||||
obj-y += cache_init.o
|
||||
obj-y += io.o
|
||||
|
||||
obj-$(CONFIG_CMD_BOOTM) += bootm.o
|
||||
|
||||
|
|
|
@ -95,6 +95,10 @@ void flush_dcache_range(ulong start_addr, ulong stop)
|
|||
const void *addr = (const void *)(start_addr & ~(lsize - 1));
|
||||
const void *aend = (const void *)((stop - 1) & ~(lsize - 1));
|
||||
|
||||
/* aend will be miscalculated when size is zero, so we return here */
|
||||
if (start_addr == stop)
|
||||
return;
|
||||
|
||||
while (1) {
|
||||
mips_cache(HIT_WRITEBACK_INV_D, addr);
|
||||
if (addr == aend)
|
||||
|
@ -109,6 +113,10 @@ void invalidate_dcache_range(ulong start_addr, ulong stop)
|
|||
const void *addr = (const void *)(start_addr & ~(lsize - 1));
|
||||
const void *aend = (const void *)((stop - 1) & ~(lsize - 1));
|
||||
|
||||
/* aend will be miscalculated when size is zero, so we return here */
|
||||
if (start_addr == stop)
|
||||
return;
|
||||
|
||||
while (1) {
|
||||
mips_cache(HIT_INVALIDATE_D, addr);
|
||||
if (addr == aend)
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
/*
|
||||
* (C) Copyright 2003
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
/*
|
||||
* mips_io_port_base is the begin of the address space to which x86 style
|
||||
* I/O ports are mapped.
|
||||
*/
|
||||
const unsigned long mips_io_port_base = -1;
|
35
arch/mips/mach-pic32/Kconfig
Normal file
35
arch/mips/mach-pic32/Kconfig
Normal file
|
@ -0,0 +1,35 @@
|
|||
menu "Microchip PIC32 platforms"
|
||||
depends on MACH_PIC32
|
||||
|
||||
config SYS_SOC
|
||||
default "pic32mzda" if SOC_PIC32MZDA
|
||||
|
||||
choice
|
||||
prompt "PIC32 SoC select"
|
||||
|
||||
config SOC_PIC32MZDA
|
||||
bool "Microchip PIC32MZ[DA] family"
|
||||
select SUPPORTS_LITTLE_ENDIAN
|
||||
select SUPPORTS_CPU_MIPS32_R1
|
||||
select SUPPORTS_CPU_MIPS32_R2
|
||||
select MIPS_L1_CACHE_SHIFT_4
|
||||
select SYS_MIPS_CACHE_INIT_RAM_LOAD
|
||||
help
|
||||
This supports Microchip PIC32MZ[DA] family of microcontrollers.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Board select"
|
||||
|
||||
config TARGET_PIC32MZDASK
|
||||
bool "Microchip PIC32MZ[DA] Starter Kit"
|
||||
depends on SOC_PIC32MZDA
|
||||
help
|
||||
This supports Microchip PIC32MZ[DA] Starter Kit.
|
||||
|
||||
endchoice
|
||||
|
||||
source "board/microchip/pic32mzda/Kconfig"
|
||||
|
||||
endmenu
|
7
arch/mips/mach-pic32/Makefile
Normal file
7
arch/mips/mach-pic32/Makefile
Normal file
|
@ -0,0 +1,7 @@
|
|||
# (C) Copyright 2015
|
||||
# Purna Chandra Mandal, purna.mandal@microchip.com.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y = cpu.o lowlevel_init.o reset.o
|
156
arch/mips/mach-pic32/cpu.c
Normal file
156
arch/mips/mach-pic32/cpu.c
Normal file
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Copyright (C) 2015
|
||||
* Purna Chandra Mandal <purna.mandal@microchip.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <mach/pic32.h>
|
||||
#include <mach/ddr.h>
|
||||
#include <dt-bindings/clock/microchip,clock.h>
|
||||
|
||||
/* Flash prefetch */
|
||||
#define PRECON 0x00
|
||||
|
||||
/* Flash ECCCON */
|
||||
#define ECC_MASK 0x03
|
||||
#define ECC_SHIFT 4
|
||||
|
||||
#define CLK_MHZ(x) ((x) / 1000000)
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static ulong clk_get_cpu_rate(void)
|
||||
{
|
||||
int ret;
|
||||
struct udevice *dev;
|
||||
|
||||
ret = uclass_get_device(UCLASS_CLK, 0, &dev);
|
||||
if (ret) {
|
||||
panic("uclass-clk: device not found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return clk_get_rate(dev);
|
||||
}
|
||||
|
||||
/* initialize prefetch module related to cpu_clk */
|
||||
static void prefetch_init(void)
|
||||
{
|
||||
struct pic32_reg_atomic *regs;
|
||||
const void __iomem *base;
|
||||
int v, nr_waits;
|
||||
ulong rate;
|
||||
|
||||
/* cpu frequency in MHZ */
|
||||
rate = clk_get_cpu_rate() / 1000000;
|
||||
|
||||
/* get flash ECC type */
|
||||
base = pic32_get_syscfg_base();
|
||||
v = (readl(base + CFGCON) >> ECC_SHIFT) & ECC_MASK;
|
||||
|
||||
if (v < 2) {
|
||||
if (rate < 66)
|
||||
nr_waits = 0;
|
||||
else if (rate < 133)
|
||||
nr_waits = 1;
|
||||
else
|
||||
nr_waits = 2;
|
||||
} else {
|
||||
if (rate <= 83)
|
||||
nr_waits = 0;
|
||||
else if (rate <= 166)
|
||||
nr_waits = 1;
|
||||
else
|
||||
nr_waits = 2;
|
||||
}
|
||||
|
||||
regs = ioremap(PREFETCH_BASE + PRECON, sizeof(*regs));
|
||||
writel(nr_waits, ®s->raw);
|
||||
|
||||
/* Enable prefetch for all */
|
||||
writel(0x30, ®s->set);
|
||||
iounmap(regs);
|
||||
}
|
||||
|
||||
/* arch specific CPU init after DM */
|
||||
int arch_cpu_init_dm(void)
|
||||
{
|
||||
/* flash prefetch */
|
||||
prefetch_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Un-gate DDR2 modules (gated by default) */
|
||||
static void ddr2_pmd_ungate(void)
|
||||
{
|
||||
void __iomem *regs;
|
||||
|
||||
regs = pic32_get_syscfg_base();
|
||||
writel(0, regs + PMD7);
|
||||
}
|
||||
|
||||
/* initialize the DDR2 Controller and DDR2 PHY */
|
||||
phys_size_t initdram(int board_type)
|
||||
{
|
||||
ddr2_pmd_ungate();
|
||||
ddr2_phy_init();
|
||||
ddr2_ctrl_init();
|
||||
return ddr2_calculate_size();
|
||||
}
|
||||
|
||||
int misc_init_r(void)
|
||||
{
|
||||
set_io_port_base(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DISPLAY_BOARDINFO
|
||||
const char *get_core_name(void)
|
||||
{
|
||||
u32 proc_id;
|
||||
const char *str;
|
||||
|
||||
proc_id = read_c0_prid();
|
||||
switch (proc_id) {
|
||||
case 0x19e28:
|
||||
str = "PIC32MZ[DA]";
|
||||
break;
|
||||
default:
|
||||
str = "UNKNOWN";
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_CMD_CLK
|
||||
int soc_clk_dump(void)
|
||||
{
|
||||
int i, ret;
|
||||
struct udevice *dev;
|
||||
|
||||
ret = uclass_get_device(UCLASS_CLK, 0, &dev);
|
||||
if (ret) {
|
||||
printf("clk-uclass not found\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
printf("PLL Speed: %lu MHz\n",
|
||||
CLK_MHZ(clk_get_periph_rate(dev, PLLCLK)));
|
||||
printf("CPU Speed: %lu MHz\n", CLK_MHZ(clk_get_rate(dev)));
|
||||
printf("MPLL Speed: %lu MHz\n",
|
||||
CLK_MHZ(clk_get_periph_rate(dev, MPLL)));
|
||||
|
||||
for (i = PB1CLK; i <= PB7CLK; i++)
|
||||
printf("PB%d Clock Speed: %lu MHz\n", i - PB1CLK + 1,
|
||||
CLK_MHZ(clk_get_periph_rate(dev, i)));
|
||||
|
||||
for (i = REF1CLK; i <= REF5CLK; i++)
|
||||
printf("REFO%d Clock Speed: %lu MHz\n", i - REF1CLK + 1,
|
||||
CLK_MHZ(clk_get_periph_rate(dev, i)));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
32
arch/mips/mach-pic32/include/mach/ddr.h
Normal file
32
arch/mips/mach-pic32/include/mach/ddr.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* (c) 2015 Purna Chandra Mandal <purna.mandal@microchip.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MICROCHIP_PIC32_DDR_H
|
||||
#define __MICROCHIP_PIC32_DDR_H
|
||||
|
||||
/* called by initdram() function */
|
||||
void ddr2_phy_init(void);
|
||||
void ddr2_ctrl_init(void);
|
||||
phys_size_t ddr2_calculate_size(void);
|
||||
|
||||
/* Maximum number of agents */
|
||||
#define NUM_AGENTS 5
|
||||
|
||||
/* Board can provide agent specific parameters for arbitration by
|
||||
* filling struct ddr2_arbiter_params for all the agents and
|
||||
* implementing board_get_ddr_arbiter_params() to return the filled
|
||||
* structure.
|
||||
*/
|
||||
struct ddr2_arbiter_params {
|
||||
u32 min_limit; /* min bursts to execute per arbitration */
|
||||
u32 req_period; /* request period threshold for accepted cmds */
|
||||
u32 min_cmd_acpt; /* min number of accepted cmds */
|
||||
};
|
||||
|
||||
const struct ddr2_arbiter_params *board_get_ddr_arbiter_params(void);
|
||||
|
||||
#endif /* __MICROCHIP_PIC32_DDR_H */
|
79
arch/mips/mach-pic32/include/mach/pic32.h
Normal file
79
arch/mips/mach-pic32/include/mach/pic32.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* (c) 2015 Paul Thacker <paul.thacker@microchip.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __PIC32_REGS_H__
|
||||
#define __PIC32_REGS_H__
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
/* System Configuration */
|
||||
#define PIC32_CFG_BASE 0x1f800000
|
||||
|
||||
/* System config register offsets */
|
||||
#define CFGCON 0x0000
|
||||
#define DEVID 0x0020
|
||||
#define SYSKEY 0x0030
|
||||
#define PMD1 0x0040
|
||||
#define PMD7 0x00a0
|
||||
#define CFGEBIA 0x00c0
|
||||
#define CFGEBIC 0x00d0
|
||||
#define CFGPG 0x00e0
|
||||
#define CFGMPLL 0x0100
|
||||
|
||||
/* Non Volatile Memory (NOR flash) */
|
||||
#define PIC32_NVM_BASE (PIC32_CFG_BASE + 0x0600)
|
||||
/* Oscillator Configuration */
|
||||
#define PIC32_OSC_BASE (PIC32_CFG_BASE + 0x1200)
|
||||
/* Peripheral Pin Select Input */
|
||||
#define PPS_IN_BASE 0x1f801400
|
||||
/* Peripheral Pin Select Output */
|
||||
#define PPS_OUT_BASE 0x1f801500
|
||||
/* Pin Config */
|
||||
#define PINCTRL_BASE 0x1f860000
|
||||
|
||||
/* USB Core */
|
||||
#define PIC32_USB_CORE_BASE 0x1f8e3000
|
||||
#define PIC32_USB_CTRL_BASE 0x1f884000
|
||||
|
||||
/* SPI1-SPI6 */
|
||||
#define PIC32_SPI1_BASE 0x1f821000
|
||||
|
||||
/* Prefetch Module */
|
||||
#define PREFETCH_BASE 0x1f8e0000
|
||||
|
||||
/* DDR2 Controller */
|
||||
#define PIC32_DDR2C_BASE 0x1f8e8000
|
||||
|
||||
/* DDR2 PHY */
|
||||
#define PIC32_DDR2P_BASE 0x1f8e9100
|
||||
|
||||
/* EBI */
|
||||
#define PIC32_EBI_BASE 0x1f8e1000
|
||||
|
||||
/* SQI */
|
||||
#define PIC32_SQI_BASE 0x1f8e2000
|
||||
|
||||
struct pic32_reg_atomic {
|
||||
u32 raw;
|
||||
u32 clr;
|
||||
u32 set;
|
||||
u32 inv;
|
||||
};
|
||||
|
||||
#define _CLR_OFFSET 0x04
|
||||
#define _SET_OFFSET 0x08
|
||||
#define _INV_OFFSET 0x0c
|
||||
|
||||
static inline void __iomem *pic32_get_syscfg_base(void)
|
||||
{
|
||||
return (void __iomem *)CKSEG1ADDR(PIC32_CFG_BASE);
|
||||
}
|
||||
|
||||
/* Core */
|
||||
const char *get_core_name(void);
|
||||
|
||||
#endif /* __PIC32_REGS_H__ */
|
27
arch/mips/mach-pic32/lowlevel_init.S
Normal file
27
arch/mips/mach-pic32/lowlevel_init.S
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* (c) 2015 Purna Chandra Mandal <purna.mandal@microchip.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/asm.h>
|
||||
|
||||
LEAF(lowlevel_init)
|
||||
/*
|
||||
* Establish Cause
|
||||
* (set IV bit)
|
||||
*/
|
||||
li t1, 0x00800000
|
||||
mtc0 t1, CP0_CAUSE
|
||||
|
||||
/* Establish Wired (and Random) */
|
||||
mtc0 zero, CP0_WIRED
|
||||
nop
|
||||
|
||||
jr ra
|
||||
nop
|
||||
END(lowlevel_init)
|
36
arch/mips/mach-pic32/reset.c
Normal file
36
arch/mips/mach-pic32/reset.c
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* (c) 2015 Purna Chandra Mandal <purna.mandal@microchip.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <mach/pic32.h>
|
||||
|
||||
/* SYSKEY */
|
||||
#define UNLOCK_KEY1 0xaa996655
|
||||
#define UNLOCK_KEY2 0x556699aa
|
||||
#define LOCK_KEY 0
|
||||
|
||||
#define RSWRST 0x1250
|
||||
|
||||
void _machine_restart(void)
|
||||
{
|
||||
void __iomem *base;
|
||||
|
||||
base = pic32_get_syscfg_base();
|
||||
|
||||
/* unlock sequence */
|
||||
writel(LOCK_KEY, base + SYSKEY);
|
||||
writel(UNLOCK_KEY1, base + SYSKEY);
|
||||
writel(UNLOCK_KEY2, base + SYSKEY);
|
||||
|
||||
/* soft reset */
|
||||
writel(0x1, base + RSWRST);
|
||||
(void) readl(base + RSWRST);
|
||||
|
||||
while (1)
|
||||
;
|
||||
}
|
|
@ -130,24 +130,26 @@ void _machine_restart(void)
|
|||
|
||||
int board_early_init_f(void)
|
||||
{
|
||||
void *io_base;
|
||||
ulong io_base;
|
||||
|
||||
/* choose correct PCI I/O base */
|
||||
switch (malta_sys_con()) {
|
||||
case SYSCON_GT64120:
|
||||
io_base = (void *)CKSEG1ADDR(MALTA_GT_PCIIO_BASE);
|
||||
io_base = CKSEG1ADDR(MALTA_GT_PCIIO_BASE);
|
||||
break;
|
||||
|
||||
case SYSCON_MSC01:
|
||||
io_base = (void *)CKSEG1ADDR(MALTA_MSC01_PCIIO_BASE);
|
||||
io_base = CKSEG1ADDR(MALTA_MSC01_PCIIO_BASE);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
set_io_port_base(io_base);
|
||||
|
||||
/* setup FDC37M817 super I/O controller */
|
||||
malta_superio_init(io_base);
|
||||
malta_superio_init();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -179,8 +181,6 @@ void pci_init_board(void)
|
|||
|
||||
switch (malta_sys_con()) {
|
||||
case SYSCON_GT64120:
|
||||
set_io_port_base(CKSEG1ADDR(MALTA_GT_PCIIO_BASE));
|
||||
|
||||
gt64120_pci_init((void *)CKSEG1ADDR(MALTA_GT_BASE),
|
||||
0x00000000, 0x00000000, CONFIG_SYS_MEM_SIZE,
|
||||
0x10000000, 0x10000000, 128 * 1024 * 1024,
|
||||
|
@ -189,8 +189,6 @@ void pci_init_board(void)
|
|||
|
||||
default:
|
||||
case SYSCON_MSC01:
|
||||
set_io_port_base(CKSEG1ADDR(MALTA_MSC01_PCIIO_BASE));
|
||||
|
||||
msc01_pci_init((void *)CKSEG1ADDR(MALTA_MSC01_PCI_BASE),
|
||||
0x00000000, 0x00000000, CONFIG_SYS_MEM_SIZE,
|
||||
MALTA_MSC01_PCIMEM_MAP,
|
||||
|
|
|
@ -45,19 +45,19 @@ static struct {
|
|||
{ SIOCONF_ACTIVATE, 0x01 },
|
||||
};
|
||||
|
||||
void malta_superio_init(void *io_base)
|
||||
void malta_superio_init(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
/* enter config state */
|
||||
writeb(SIOCONF_ENTER_SETUP, io_base + SIO_CONF_PORT);
|
||||
outb(SIOCONF_ENTER_SETUP, SIO_CONF_PORT);
|
||||
|
||||
/* configure peripherals */
|
||||
for (i = 0; i < ARRAY_SIZE(sio_config); i++) {
|
||||
writeb(sio_config[i].key, io_base + SIO_CONF_PORT);
|
||||
writeb(sio_config[i].data, io_base + SIO_DATA_PORT);
|
||||
outb(sio_config[i].key, SIO_CONF_PORT);
|
||||
outb(sio_config[i].data, SIO_DATA_PORT);
|
||||
}
|
||||
|
||||
/* exit config state */
|
||||
writeb(SIOCONF_EXIT_SETUP, io_base + SIO_CONF_PORT);
|
||||
outb(SIOCONF_EXIT_SETUP, SIO_CONF_PORT);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,6 @@
|
|||
#ifndef __BOARD_MALTA_SUPERIO_H__
|
||||
#define __BOARD_MALTA_SUPERIO_H__
|
||||
|
||||
extern void malta_superio_init(void *io_base);
|
||||
void malta_superio_init(void);
|
||||
|
||||
#endif /* __BOARD_MALTA_SUPERIO_H__ */
|
||||
|
|
13
board/microchip/pic32mzda/Kconfig
Normal file
13
board/microchip/pic32mzda/Kconfig
Normal file
|
@ -0,0 +1,13 @@
|
|||
|
||||
if TARGET_PIC32MZDASK
|
||||
|
||||
config SYS_BOARD
|
||||
default "pic32mzda"
|
||||
|
||||
config SYS_VENDOR
|
||||
default "microchip"
|
||||
|
||||
config SYS_CONFIG_NAME
|
||||
default "pic32mzdask"
|
||||
|
||||
endif
|
6
board/microchip/pic32mzda/MAINTAINERS
Normal file
6
board/microchip/pic32mzda/MAINTAINERS
Normal file
|
@ -0,0 +1,6 @@
|
|||
PIC32MZDASK BOARD
|
||||
M: Purna Chandra Mandal <purna.mandal@microchip.com>
|
||||
S: Maintained
|
||||
F: board/microchip/pic32mzda/
|
||||
F: include/configs/pic32mzdask.h
|
||||
F: configs/pic32mzdask_defconfig
|
7
board/microchip/pic32mzda/Makefile
Normal file
7
board/microchip/pic32mzda/Makefile
Normal file
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
# (C) Copyright 2015
|
||||
# Purna Chandra Mandal, purna.mandal@microchip.com.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
obj-y := pic32mzda.o
|
22
board/microchip/pic32mzda/README
Normal file
22
board/microchip/pic32mzda/README
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* (c) 2015 Purna Chandra Mandal <purna.mandal@microchip.com>
|
||||
*/
|
||||
|
||||
PIC32MZ[DA] Starter Kit
|
||||
----------------------------------------
|
||||
PIC32MZ[DA] Starter Kit is based on PIC32MZ[DA] family of micro-controller.
|
||||
This family is powered by MIPS M14KEC 32bit general purpose core and has
|
||||
advanced microcontroller features and peripherals.
|
||||
|
||||
This processor boots with proprietary stage1 bootloader running from internal
|
||||
boot-flash. Stage1 bootloader inturns locates and jumps to U-Boot programmed
|
||||
on internal program-flash. Finally U-Boot loads OS image (along with other
|
||||
required files for booting) from either uSD card, or ethernet, or from USB
|
||||
storage.
|
||||
|
||||
To boot Linux following three files are mandatory - uEnv.txt (custom U-Boot
|
||||
environment file), uImage, *.dtb (platform device-tree-blob file).
|
||||
|
||||
U-Boot jumps to Linux using UHI specification.
|
||||
|
||||
Visit http://microchip.com for details.
|
31
board/microchip/pic32mzda/pic32mzda.c
Normal file
31
board/microchip/pic32mzda/pic32mzda.c
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Microchip PIC32MZ[DA] Starter Kit board
|
||||
*
|
||||
* Copyright (C) 2015, Microchip Technology Inc.
|
||||
* Purna Chandra Mandal <purna.mandal@microchip.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <clk.h>
|
||||
#include <mach/pic32.h>
|
||||
|
||||
#ifdef CONFIG_DISPLAY_BOARDINFO
|
||||
int checkboard(void)
|
||||
{
|
||||
ulong rate = 0;
|
||||
struct udevice *dev;
|
||||
|
||||
printf("Core: %s\n", get_core_name());
|
||||
|
||||
if (!uclass_get_device(UCLASS_CLK, 0, &dev)) {
|
||||
rate = clk_get_rate(dev);
|
||||
printf("CPU Speed: %lu MHz\n", rate / 1000000);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
34
configs/pic32mzdask_defconfig
Normal file
34
configs/pic32mzdask_defconfig
Normal file
|
@ -0,0 +1,34 @@
|
|||
CONFIG_MIPS=y
|
||||
CONFIG_SYS_MALLOC_F_LEN=0x600
|
||||
CONFIG_DM_SERIAL=y
|
||||
CONFIG_DM_GPIO=y
|
||||
CONFIG_MACH_PIC32=y
|
||||
# CONFIG_MIPS_BOOT_ENV_LEGACY is not set
|
||||
CONFIG_MIPS_BOOT_FDT=y
|
||||
CONFIG_DEFAULT_DEVICE_TREE="pic32mzda_sk"
|
||||
CONFIG_HUSH_PARSER=y
|
||||
CONFIG_SYS_PROMPT="dask # "
|
||||
# CONFIG_CMD_IMLS is not set
|
||||
# CONFIG_CMD_SAVEENV is not set
|
||||
CONFIG_LOOPW=y
|
||||
CONFIG_CMD_MEMTEST=y
|
||||
CONFIG_CMD_MEMINFO=y
|
||||
# CONFIG_CMD_FLASH is not set
|
||||
# CONFIG_CMD_FPGA is not set
|
||||
CONFIG_CMD_GPIO=y
|
||||
CONFIG_CMD_RARP=y
|
||||
CONFIG_CMD_DHCP=y
|
||||
CONFIG_CMD_PING=y
|
||||
CONFIG_CMD_TIME=y
|
||||
CONFIG_OF_EMBED=y
|
||||
CONFIG_NET_RANDOM_ETHADDR=y
|
||||
CONFIG_CLK=y
|
||||
CONFIG_DM_MMC=y
|
||||
CONFIG_PIC32_SDHCI=y
|
||||
CONFIG_DM_ETH=y
|
||||
CONFIG_PIC32_ETH=y
|
||||
CONFIG_PINCTRL=y
|
||||
# CONFIG_PINCTRL_FULL is not set
|
||||
CONFIG_SYS_VSNPRINTF=y
|
||||
CONFIG_USE_TINY_PRINTF=y
|
||||
CONFIG_CMD_DHRYSTONE=y
|
33
doc/device-tree-bindings/clock/microchip,pic32-clock.txt
Normal file
33
doc/device-tree-bindings/clock/microchip,pic32-clock.txt
Normal file
|
@ -0,0 +1,33 @@
|
|||
* Microchip PIC32 Clock and Oscillator
|
||||
|
||||
Microchip PIC32 clock tree consists of few oscillators, PLLs,
|
||||
multiplexers and few divider modules capable of supplying clocks
|
||||
to various controllers within SoC and also to off-chip.
|
||||
|
||||
PIC32 clock controller output is defined by indices as defined
|
||||
in [0]
|
||||
|
||||
[0] include/dt-bindings/clock/microchip,clock.h
|
||||
|
||||
Required Properties:
|
||||
- compatible: should be "microchip,pic32mzda_clk"
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- #clock-cells: should be 1.
|
||||
|
||||
Example: Clock controller node:
|
||||
|
||||
clock: clk@1f801200 {
|
||||
compatible = "microchip,pic32mzda-clk";
|
||||
reg = <0x1f801200 0x1000>;
|
||||
};
|
||||
|
||||
Example: UART controller node that consumes the clock generated by the clock
|
||||
controller:
|
||||
|
||||
uart1: serial@1f822000 {
|
||||
compatible = "microchip,pic32mzda-uart";
|
||||
reg = <0xbf822000 0x50>;
|
||||
interrupts = <112 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clock PB2CLK>;
|
||||
};
|
5
doc/device-tree-bindings/serial/microchip,pic32-uart.txt
Normal file
5
doc/device-tree-bindings/serial/microchip,pic32-uart.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
* Microchip PIC32 serial UART
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "microchip,pic32mzda-uart".
|
||||
- reg: exactly one register range.
|
|
@ -69,4 +69,5 @@ obj-y += soc/
|
|||
obj-$(CONFIG_REMOTEPROC) += remoteproc/
|
||||
obj-y += thermal/
|
||||
|
||||
obj-$(CONFIG_MACH_PIC32) += ddr/microchip/
|
||||
endif
|
||||
|
|
|
@ -9,3 +9,4 @@ obj-$(CONFIG_CLK) += clk-uclass.o clk_fixed_rate.o
|
|||
obj-$(CONFIG_ROCKCHIP_RK3036) += clk_rk3036.o
|
||||
obj-$(CONFIG_ROCKCHIP_RK3288) += clk_rk3288.o
|
||||
obj-$(CONFIG_SANDBOX) += clk_sandbox.o
|
||||
obj-$(CONFIG_MACH_PIC32) += clk_pic32.o
|
||||
|
|
433
drivers/clk/clk_pic32.c
Normal file
433
drivers/clk/clk_pic32.c
Normal file
|
@ -0,0 +1,433 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Purna Chandra Mandal <purna.mandal@microchip.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <div64.h>
|
||||
#include <wait_bit.h>
|
||||
#include <dm/lists.h>
|
||||
#include <asm/io.h>
|
||||
#include <mach/pic32.h>
|
||||
#include <dt-bindings/clock/microchip,clock.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/* Primary oscillator */
|
||||
#define SYS_POSC_CLK_HZ 24000000
|
||||
|
||||
/* FRC clk rate */
|
||||
#define SYS_FRC_CLK_HZ 8000000
|
||||
|
||||
/* Clock Registers */
|
||||
#define OSCCON 0x0000
|
||||
#define OSCTUNE 0x0010
|
||||
#define SPLLCON 0x0020
|
||||
#define REFO1CON 0x0080
|
||||
#define REFO1TRIM 0x0090
|
||||
#define PB1DIV 0x0140
|
||||
|
||||
/* SPLL */
|
||||
#define ICLK_MASK 0x00000080
|
||||
#define PLLIDIV_MASK 0x00000007
|
||||
#define PLLODIV_MASK 0x00000007
|
||||
#define CUROSC_MASK 0x00000007
|
||||
#define PLLMUL_MASK 0x0000007F
|
||||
#define FRCDIV_MASK 0x00000007
|
||||
|
||||
/* PBCLK */
|
||||
#define PBDIV_MASK 0x00000007
|
||||
|
||||
/* SYSCLK MUX */
|
||||
#define SCLK_SRC_FRC1 0
|
||||
#define SCLK_SRC_SPLL 1
|
||||
#define SCLK_SRC_POSC 2
|
||||
#define SCLK_SRC_FRC2 7
|
||||
|
||||
/* Reference Oscillator Control Reg fields */
|
||||
#define REFO_SEL_MASK 0x0f
|
||||
#define REFO_SEL_SHIFT 0
|
||||
#define REFO_ACTIVE BIT(8)
|
||||
#define REFO_DIVSW_EN BIT(9)
|
||||
#define REFO_OE BIT(12)
|
||||
#define REFO_ON BIT(15)
|
||||
#define REFO_DIV_SHIFT 16
|
||||
#define REFO_DIV_MASK 0x7fff
|
||||
|
||||
/* Reference Oscillator Trim Register Fields */
|
||||
#define REFO_TRIM_REG 0x10
|
||||
#define REFO_TRIM_MASK 0x1ff
|
||||
#define REFO_TRIM_SHIFT 23
|
||||
#define REFO_TRIM_MAX 511
|
||||
|
||||
#define ROCLK_SRC_SCLK 0x0
|
||||
#define ROCLK_SRC_SPLL 0x7
|
||||
#define ROCLK_SRC_ROCLKI 0x8
|
||||
|
||||
/* Memory PLL */
|
||||
#define MPLL_IDIV 0x3f
|
||||
#define MPLL_MULT 0xff
|
||||
#define MPLL_ODIV1 0x7
|
||||
#define MPLL_ODIV2 0x7
|
||||
#define MPLL_VREG_RDY BIT(23)
|
||||
#define MPLL_RDY BIT(31)
|
||||
#define MPLL_IDIV_SHIFT 0
|
||||
#define MPLL_MULT_SHIFT 8
|
||||
#define MPLL_ODIV1_SHIFT 24
|
||||
#define MPLL_ODIV2_SHIFT 27
|
||||
#define MPLL_IDIV_INIT 0x03
|
||||
#define MPLL_MULT_INIT 0x32
|
||||
#define MPLL_ODIV1_INIT 0x02
|
||||
#define MPLL_ODIV2_INIT 0x01
|
||||
|
||||
struct pic32_clk_priv {
|
||||
void __iomem *iobase;
|
||||
void __iomem *syscfg_base;
|
||||
};
|
||||
|
||||
static ulong pic32_get_pll_rate(struct pic32_clk_priv *priv)
|
||||
{
|
||||
u32 iclk, idiv, odiv, mult;
|
||||
ulong plliclk, v;
|
||||
|
||||
v = readl(priv->iobase + SPLLCON);
|
||||
iclk = (v & ICLK_MASK);
|
||||
idiv = ((v >> 8) & PLLIDIV_MASK) + 1;
|
||||
odiv = ((v >> 24) & PLLODIV_MASK);
|
||||
mult = ((v >> 16) & PLLMUL_MASK) + 1;
|
||||
|
||||
plliclk = iclk ? SYS_FRC_CLK_HZ : SYS_POSC_CLK_HZ;
|
||||
|
||||
if (odiv < 2)
|
||||
odiv = 2;
|
||||
else if (odiv < 5)
|
||||
odiv = (1 << odiv);
|
||||
else
|
||||
odiv = 32;
|
||||
|
||||
return ((plliclk / idiv) * mult) / odiv;
|
||||
}
|
||||
|
||||
static ulong pic32_get_sysclk(struct pic32_clk_priv *priv)
|
||||
{
|
||||
ulong v;
|
||||
ulong hz;
|
||||
ulong div, frcdiv;
|
||||
ulong curr_osc;
|
||||
|
||||
/* get clk source */
|
||||
v = readl(priv->iobase + OSCCON);
|
||||
curr_osc = (v >> 12) & CUROSC_MASK;
|
||||
switch (curr_osc) {
|
||||
case SCLK_SRC_FRC1:
|
||||
case SCLK_SRC_FRC2:
|
||||
frcdiv = ((v >> 24) & FRCDIV_MASK);
|
||||
div = ((1 << frcdiv) + 1) + (128 * (frcdiv == 7));
|
||||
hz = SYS_FRC_CLK_HZ / div;
|
||||
break;
|
||||
|
||||
case SCLK_SRC_SPLL:
|
||||
hz = pic32_get_pll_rate(priv);
|
||||
break;
|
||||
|
||||
case SCLK_SRC_POSC:
|
||||
hz = SYS_POSC_CLK_HZ;
|
||||
break;
|
||||
|
||||
default:
|
||||
hz = 0;
|
||||
printf("clk: unknown sclk_src.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return hz;
|
||||
}
|
||||
|
||||
static ulong pic32_get_pbclk(struct pic32_clk_priv *priv, int periph)
|
||||
{
|
||||
void __iomem *reg;
|
||||
ulong div, clk_freq;
|
||||
|
||||
WARN_ON((periph < PB1CLK) || (periph > PB7CLK));
|
||||
|
||||
clk_freq = pic32_get_sysclk(priv);
|
||||
|
||||
reg = priv->iobase + PB1DIV + (periph - PB1CLK) * 0x10;
|
||||
div = (readl(reg) & PBDIV_MASK) + 1;
|
||||
|
||||
return clk_freq / div;
|
||||
}
|
||||
|
||||
static ulong pic32_get_cpuclk(struct pic32_clk_priv *priv)
|
||||
{
|
||||
return pic32_get_pbclk(priv, PB7CLK);
|
||||
}
|
||||
|
||||
static ulong pic32_set_refclk(struct pic32_clk_priv *priv, int periph,
|
||||
int parent_rate, int rate, int parent_id)
|
||||
{
|
||||
void __iomem *reg;
|
||||
u32 div, trim, v;
|
||||
u64 frac;
|
||||
|
||||
WARN_ON((periph < REF1CLK) || (periph > REF5CLK));
|
||||
|
||||
/* calculate dividers,
|
||||
* rate = parent_rate / [2 * (div + (trim / 512))]
|
||||
*/
|
||||
if (parent_rate <= rate) {
|
||||
div = 0;
|
||||
trim = 0;
|
||||
} else {
|
||||
div = parent_rate / (rate << 1);
|
||||
frac = parent_rate;
|
||||
frac <<= 8;
|
||||
do_div(frac, rate);
|
||||
frac -= (u64)(div << 9);
|
||||
trim = (frac >= REFO_TRIM_MAX) ? REFO_TRIM_MAX : (u32)frac;
|
||||
}
|
||||
|
||||
reg = priv->iobase + REFO1CON + (periph - REF1CLK) * 0x20;
|
||||
|
||||
/* disable clk */
|
||||
writel(REFO_ON | REFO_OE, reg + _CLR_OFFSET);
|
||||
|
||||
/* wait till previous src change is active */
|
||||
wait_for_bit(__func__, reg, REFO_DIVSW_EN | REFO_ACTIVE,
|
||||
false, CONFIG_SYS_HZ, false);
|
||||
|
||||
/* parent_id */
|
||||
v = readl(reg);
|
||||
v &= ~(REFO_SEL_MASK << REFO_SEL_SHIFT);
|
||||
v |= (parent_id << REFO_SEL_SHIFT);
|
||||
|
||||
/* apply rodiv */
|
||||
v &= ~(REFO_DIV_MASK << REFO_DIV_SHIFT);
|
||||
v |= (div << REFO_DIV_SHIFT);
|
||||
writel(v, reg);
|
||||
|
||||
/* apply trim */
|
||||
v = readl(reg + REFO_TRIM_REG);
|
||||
v &= ~(REFO_TRIM_MASK << REFO_TRIM_SHIFT);
|
||||
v |= (trim << REFO_TRIM_SHIFT);
|
||||
writel(v, reg + REFO_TRIM_REG);
|
||||
|
||||
/* enable clk */
|
||||
writel(REFO_ON | REFO_OE, reg + _SET_OFFSET);
|
||||
|
||||
/* switch divider */
|
||||
writel(REFO_DIVSW_EN, reg + _SET_OFFSET);
|
||||
|
||||
/* wait for divider switching to complete */
|
||||
return wait_for_bit(__func__, reg, REFO_DIVSW_EN, false,
|
||||
CONFIG_SYS_HZ, false);
|
||||
}
|
||||
|
||||
static ulong pic32_get_refclk(struct pic32_clk_priv *priv, int periph)
|
||||
{
|
||||
u32 rodiv, rotrim, rosel, v, parent_rate;
|
||||
void __iomem *reg;
|
||||
u64 rate64;
|
||||
|
||||
WARN_ON((periph < REF1CLK) || (periph > REF5CLK));
|
||||
|
||||
reg = priv->iobase + REFO1CON + (periph - REF1CLK) * 0x20;
|
||||
v = readl(reg);
|
||||
/* get rosel */
|
||||
rosel = (v >> REFO_SEL_SHIFT) & REFO_SEL_MASK;
|
||||
/* get div */
|
||||
rodiv = (v >> REFO_DIV_SHIFT) & REFO_DIV_MASK;
|
||||
|
||||
/* get trim */
|
||||
v = readl(reg + REFO_TRIM_REG);
|
||||
rotrim = (v >> REFO_TRIM_SHIFT) & REFO_TRIM_MASK;
|
||||
|
||||
if (!rodiv)
|
||||
return 0;
|
||||
|
||||
/* get parent rate */
|
||||
switch (rosel) {
|
||||
case ROCLK_SRC_SCLK:
|
||||
parent_rate = pic32_get_cpuclk(priv);
|
||||
break;
|
||||
case ROCLK_SRC_SPLL:
|
||||
parent_rate = pic32_get_pll_rate(priv);
|
||||
break;
|
||||
default:
|
||||
parent_rate = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Calculation
|
||||
* rate = parent_rate / [2 * (div + (trim / 512))]
|
||||
*/
|
||||
if (rotrim) {
|
||||
rodiv <<= 9;
|
||||
rodiv += rotrim;
|
||||
rate64 = parent_rate;
|
||||
rate64 <<= 8;
|
||||
do_div(rate64, rodiv);
|
||||
v = (u32)rate64;
|
||||
} else {
|
||||
v = parent_rate / (rodiv << 1);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
static ulong pic32_get_mpll_rate(struct pic32_clk_priv *priv)
|
||||
{
|
||||
u32 v, idiv, mul;
|
||||
u32 odiv1, odiv2;
|
||||
u64 rate;
|
||||
|
||||
v = readl(priv->syscfg_base + CFGMPLL);
|
||||
idiv = v & MPLL_IDIV;
|
||||
mul = (v >> MPLL_MULT_SHIFT) & MPLL_MULT;
|
||||
odiv1 = (v >> MPLL_ODIV1_SHIFT) & MPLL_ODIV1;
|
||||
odiv2 = (v >> MPLL_ODIV2_SHIFT) & MPLL_ODIV2;
|
||||
|
||||
rate = (SYS_POSC_CLK_HZ / idiv) * mul;
|
||||
do_div(rate, odiv1);
|
||||
do_div(rate, odiv2);
|
||||
|
||||
return (ulong)rate;
|
||||
}
|
||||
|
||||
static int pic32_mpll_init(struct pic32_clk_priv *priv)
|
||||
{
|
||||
u32 v, mask;
|
||||
|
||||
/* initialize */
|
||||
v = (MPLL_IDIV_INIT << MPLL_IDIV_SHIFT) |
|
||||
(MPLL_MULT_INIT << MPLL_MULT_SHIFT) |
|
||||
(MPLL_ODIV1_INIT << MPLL_ODIV1_SHIFT) |
|
||||
(MPLL_ODIV2_INIT << MPLL_ODIV2_SHIFT);
|
||||
|
||||
writel(v, priv->syscfg_base + CFGMPLL);
|
||||
|
||||
/* Wait for ready */
|
||||
mask = MPLL_RDY | MPLL_VREG_RDY;
|
||||
return wait_for_bit(__func__, priv->syscfg_base + CFGMPLL, mask,
|
||||
true, get_tbclk(), false);
|
||||
}
|
||||
|
||||
static void pic32_clk_init(struct udevice *dev)
|
||||
{
|
||||
const void *blob = gd->fdt_blob;
|
||||
struct pic32_clk_priv *priv;
|
||||
ulong rate, pll_hz;
|
||||
char propname[50];
|
||||
int i;
|
||||
|
||||
priv = dev_get_priv(dev);
|
||||
pll_hz = pic32_get_pll_rate(priv);
|
||||
|
||||
/* Initialize REFOs as not initialized and enabled on reset. */
|
||||
for (i = REF1CLK; i <= REF5CLK; i++) {
|
||||
snprintf(propname, sizeof(propname),
|
||||
"microchip,refo%d-frequency", i - REF1CLK + 1);
|
||||
rate = fdtdec_get_int(blob, dev->of_offset, propname, 0);
|
||||
if (rate)
|
||||
pic32_set_refclk(priv, i, pll_hz, rate, ROCLK_SRC_SPLL);
|
||||
}
|
||||
|
||||
/* Memory PLL */
|
||||
pic32_mpll_init(priv);
|
||||
}
|
||||
|
||||
static ulong pic32_clk_get_rate(struct udevice *dev)
|
||||
{
|
||||
struct pic32_clk_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return pic32_get_cpuclk(priv);
|
||||
}
|
||||
|
||||
static ulong pic32_get_periph_rate(struct udevice *dev, int periph)
|
||||
{
|
||||
struct pic32_clk_priv *priv = dev_get_priv(dev);
|
||||
ulong rate;
|
||||
|
||||
switch (periph) {
|
||||
case PB1CLK ... PB7CLK:
|
||||
rate = pic32_get_pbclk(priv, periph);
|
||||
break;
|
||||
case REF1CLK ... REF5CLK:
|
||||
rate = pic32_get_refclk(priv, periph);
|
||||
break;
|
||||
case PLLCLK:
|
||||
rate = pic32_get_pll_rate(priv);
|
||||
break;
|
||||
case MPLL:
|
||||
rate = pic32_get_mpll_rate(priv);
|
||||
break;
|
||||
default:
|
||||
rate = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static ulong pic32_set_periph_rate(struct udevice *dev, int periph, ulong rate)
|
||||
{
|
||||
struct pic32_clk_priv *priv = dev_get_priv(dev);
|
||||
ulong pll_hz;
|
||||
|
||||
switch (periph) {
|
||||
case REF1CLK ... REF5CLK:
|
||||
pll_hz = pic32_get_pll_rate(priv);
|
||||
pic32_set_refclk(priv, periph, pll_hz, rate, ROCLK_SRC_SPLL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static struct clk_ops pic32_pic32_clk_ops = {
|
||||
.get_rate = pic32_clk_get_rate,
|
||||
.set_periph_rate = pic32_set_periph_rate,
|
||||
.get_periph_rate = pic32_get_periph_rate,
|
||||
};
|
||||
|
||||
static int pic32_clk_probe(struct udevice *dev)
|
||||
{
|
||||
struct pic32_clk_priv *priv = dev_get_priv(dev);
|
||||
fdt_addr_t addr;
|
||||
fdt_size_t size;
|
||||
|
||||
addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg", &size);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
priv->iobase = ioremap(addr, size);
|
||||
if (!priv->iobase)
|
||||
return -EINVAL;
|
||||
|
||||
priv->syscfg_base = pic32_get_syscfg_base();
|
||||
|
||||
/* initialize clocks */
|
||||
pic32_clk_init(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id pic32_clk_ids[] = {
|
||||
{ .compatible = "microchip,pic32mzda-clk"},
|
||||
{}
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(pic32_clk) = {
|
||||
.name = "pic32_clk",
|
||||
.id = UCLASS_CLK,
|
||||
.of_match = pic32_clk_ids,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
.ops = &pic32_pic32_clk_ops,
|
||||
.probe = pic32_clk_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct pic32_clk_priv),
|
||||
};
|
6
drivers/ddr/microchip/Makefile
Normal file
6
drivers/ddr/microchip/Makefile
Normal file
|
@ -0,0 +1,6 @@
|
|||
#
|
||||
# Copyright (C) 2015 Microchip Technology Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
obj-$(CONFIG_MACH_PIC32) += ddr2.o
|
278
drivers/ddr/microchip/ddr2.c
Normal file
278
drivers/ddr/microchip/ddr2.c
Normal file
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* (c) 2015 Paul Thacker <paul.thacker@microchip.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <wait_bit.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <mach/pic32.h>
|
||||
#include <mach/ddr.h>
|
||||
|
||||
#include "ddr2_regs.h"
|
||||
#include "ddr2_timing.h"
|
||||
|
||||
/* init DDR2 Phy */
|
||||
void ddr2_phy_init(void)
|
||||
{
|
||||
struct ddr2_phy_regs *ddr2_phy;
|
||||
u32 pad_ctl;
|
||||
|
||||
ddr2_phy = ioremap(PIC32_DDR2P_BASE, sizeof(*ddr2_phy));
|
||||
|
||||
/* PHY_DLL_RECALIB */
|
||||
writel(DELAY_START_VAL(3) | DISABLE_RECALIB(0) |
|
||||
RECALIB_CNT(0x10), &ddr2_phy->dll_recalib);
|
||||
|
||||
/* PHY_PAD_CTRL */
|
||||
pad_ctl = ODT_SEL | ODT_EN | DRIVE_SEL(0) |
|
||||
ODT_PULLDOWN(2) | ODT_PULLUP(3) |
|
||||
EXTRA_OEN_CLK(0) | NOEXT_DLL |
|
||||
DLR_DFT_WRCMD | HALF_RATE |
|
||||
DRVSTR_PFET(0xe) | DRVSTR_NFET(0xe) |
|
||||
RCVR_EN | PREAMBLE_DLY(2);
|
||||
writel(pad_ctl, &ddr2_phy->pad_ctrl);
|
||||
|
||||
/* SCL_CONFIG_0 */
|
||||
writel(SCL_BURST8 | SCL_DDR_CONNECTED | SCL_RCAS_LAT(RL) |
|
||||
SCL_ODTCSWW, &ddr2_phy->scl_config_1);
|
||||
|
||||
/* SCL_CONFIG_1 */
|
||||
writel(SCL_CSEN | SCL_WCAS_LAT(WL), &ddr2_phy->scl_config_2);
|
||||
|
||||
/* SCL_LAT */
|
||||
writel(SCL_CAPCLKDLY(3) | SCL_DDRCLKDLY(4), &ddr2_phy->scl_latency);
|
||||
}
|
||||
|
||||
/* start phy self calibration logic */
|
||||
static int ddr2_phy_calib_start(void)
|
||||
{
|
||||
struct ddr2_phy_regs *ddr2_phy;
|
||||
|
||||
ddr2_phy = ioremap(PIC32_DDR2P_BASE, sizeof(*ddr2_phy));
|
||||
|
||||
/* DDR Phy SCL Start */
|
||||
writel(SCL_START | SCL_EN, &ddr2_phy->scl_start);
|
||||
|
||||
/* Wait for SCL for data byte to pass */
|
||||
return wait_for_bit(__func__, &ddr2_phy->scl_start, SCL_LUBPASS,
|
||||
true, CONFIG_SYS_HZ, false);
|
||||
}
|
||||
|
||||
/* DDR2 Controller initialization */
|
||||
|
||||
/* Target Agent Arbiter */
|
||||
static void ddr_set_arbiter(struct ddr2_ctrl_regs *ctrl,
|
||||
const struct ddr2_arbiter_params *const param)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_AGENTS; i++) {
|
||||
/* set min burst size */
|
||||
writel(i * MIN_LIM_WIDTH, &ctrl->tsel);
|
||||
writel(param->min_limit, &ctrl->minlim);
|
||||
|
||||
/* set request period (4 * req_period clocks) */
|
||||
writel(i * RQST_PERIOD_WIDTH, &ctrl->tsel);
|
||||
writel(param->req_period, &ctrl->reqprd);
|
||||
|
||||
/* set number of burst accepted */
|
||||
writel(i * MIN_CMDACPT_WIDTH, &ctrl->tsel);
|
||||
writel(param->min_cmd_acpt, &ctrl->mincmd);
|
||||
}
|
||||
}
|
||||
|
||||
const struct ddr2_arbiter_params *__weak board_get_ddr_arbiter_params(void)
|
||||
{
|
||||
/* default arbiter parameters */
|
||||
static const struct ddr2_arbiter_params arb_params[] = {
|
||||
{ .min_limit = 0x1f, .req_period = 0xff, .min_cmd_acpt = 0x04,},
|
||||
{ .min_limit = 0x1f, .req_period = 0xff, .min_cmd_acpt = 0x10,},
|
||||
{ .min_limit = 0x1f, .req_period = 0xff, .min_cmd_acpt = 0x10,},
|
||||
{ .min_limit = 0x04, .req_period = 0xff, .min_cmd_acpt = 0x04,},
|
||||
{ .min_limit = 0x04, .req_period = 0xff, .min_cmd_acpt = 0x04,},
|
||||
};
|
||||
|
||||
return &arb_params[0];
|
||||
}
|
||||
|
||||
static void host_load_cmd(struct ddr2_ctrl_regs *ctrl, u32 cmd_idx,
|
||||
u32 hostcmd2, u32 hostcmd1, u32 delay)
|
||||
{
|
||||
u32 hc_delay;
|
||||
|
||||
hc_delay = max_t(u32, DIV_ROUND_UP(delay, T_CK), 2) - 2;
|
||||
writel(hostcmd1, &ctrl->cmd10[cmd_idx]);
|
||||
writel((hostcmd2 & 0x7ff) | (hc_delay << 11), &ctrl->cmd20[cmd_idx]);
|
||||
}
|
||||
|
||||
/* init DDR2 Controller */
|
||||
void ddr2_ctrl_init(void)
|
||||
{
|
||||
u32 wr2prech, rd2prech, wr2rd, wr2rd_cs;
|
||||
u32 ras2ras, ras2cas, prech2ras, temp;
|
||||
const struct ddr2_arbiter_params *arb_params;
|
||||
struct ddr2_ctrl_regs *ctrl;
|
||||
|
||||
ctrl = ioremap(PIC32_DDR2C_BASE, sizeof(*ctrl));
|
||||
|
||||
/* PIC32 DDR2 controller always work in HALF_RATE */
|
||||
writel(HALF_RATE_MODE, &ctrl->memwidth);
|
||||
|
||||
/* Set arbiter configuration per target */
|
||||
arb_params = board_get_ddr_arbiter_params();
|
||||
ddr_set_arbiter(ctrl, arb_params);
|
||||
|
||||
/* Address Configuration, model {CS, ROW, BA, COL} */
|
||||
writel((ROW_ADDR_RSHIFT | (BA_RSHFT << 8) | (CS_ADDR_RSHIFT << 16) |
|
||||
(COL_HI_RSHFT << 24) | (SB_PRI << 29) |
|
||||
(EN_AUTO_PRECH << 30)), &ctrl->memcfg0);
|
||||
|
||||
writel(ROW_ADDR_MASK, &ctrl->memcfg1);
|
||||
writel(COL_HI_MASK, &ctrl->memcfg2);
|
||||
writel(COL_LO_MASK, &ctrl->memcfg3);
|
||||
writel(BA_MASK | (CS_ADDR_MASK << 8), &ctrl->memcfg4);
|
||||
|
||||
/* Refresh Config */
|
||||
writel(REFCNT_CLK(DIV_ROUND_UP(T_RFI, T_CK_CTRL) - 2) |
|
||||
REFDLY_CLK(DIV_ROUND_UP(T_RFC_MIN, T_CK_CTRL) - 2) |
|
||||
MAX_PEND_REF(7),
|
||||
&ctrl->refcfg);
|
||||
|
||||
/* Power Config */
|
||||
writel(ECC_EN(0) | ERR_CORR_EN(0) | EN_AUTO_PWR_DN(0) |
|
||||
EN_AUTO_SELF_REF(3) | PWR_DN_DLY(8) |
|
||||
SELF_REF_DLY(17) | PRECH_PWR_DN_ONLY(0),
|
||||
&ctrl->pwrcfg);
|
||||
|
||||
/* Delay Config */
|
||||
wr2rd = max_t(u32, DIV_ROUND_UP(T_WTR, T_CK_CTRL),
|
||||
DIV_ROUND_UP(T_WTR_TCK, 2)) + WL + BL;
|
||||
wr2rd_cs = max_t(u32, wr2rd - 1, 3);
|
||||
wr2prech = DIV_ROUND_UP(T_WR, T_CK_CTRL) + WL + BL;
|
||||
rd2prech = max_t(u32, DIV_ROUND_UP(T_RTP, T_CK_CTRL),
|
||||
DIV_ROUND_UP(T_RTP_TCK, 2)) + BL - 2;
|
||||
ras2ras = max_t(u32, DIV_ROUND_UP(T_RRD, T_CK_CTRL),
|
||||
DIV_ROUND_UP(T_RRD_TCK, 2)) - 1;
|
||||
ras2cas = DIV_ROUND_UP(T_RCD, T_CK_CTRL) - 1;
|
||||
prech2ras = DIV_ROUND_UP(T_RP, T_CK_CTRL) - 1;
|
||||
|
||||
writel(((wr2rd & 0x0f) |
|
||||
((wr2rd_cs & 0x0f) << 4) |
|
||||
((BL - 1) << 8) |
|
||||
(BL << 12) |
|
||||
((BL - 1) << 16) |
|
||||
((BL - 1) << 20) |
|
||||
((BL + 2) << 24) |
|
||||
((RL - WL + 3) << 28)), &ctrl->dlycfg0);
|
||||
|
||||
writel(((T_CKE_TCK - 1) |
|
||||
(((DIV_ROUND_UP(T_DLLK, 2) - 2) & 0xff) << 8) |
|
||||
((T_CKE_TCK - 1) << 16) |
|
||||
((max_t(u32, T_XP_TCK, T_CKE_TCK) - 1) << 20) |
|
||||
((wr2prech >> 4) << 26) |
|
||||
((wr2rd >> 4) << 27) |
|
||||
((wr2rd_cs >> 4) << 28) |
|
||||
(((RL + 5) >> 4) << 29) |
|
||||
((DIV_ROUND_UP(T_DLLK, 2) >> 8) << 30)), &ctrl->dlycfg1);
|
||||
|
||||
writel((DIV_ROUND_UP(T_RP, T_CK_CTRL) |
|
||||
(rd2prech << 8) |
|
||||
((wr2prech & 0x0f) << 12) |
|
||||
(ras2ras << 16) |
|
||||
(ras2cas << 20) |
|
||||
(prech2ras << 24) |
|
||||
((RL + 3) << 28)), &ctrl->dlycfg2);
|
||||
|
||||
writel(((DIV_ROUND_UP(T_RAS_MIN, T_CK_CTRL) - 1) |
|
||||
((DIV_ROUND_UP(T_RC, T_CK_CTRL) - 1) << 8) |
|
||||
((DIV_ROUND_UP(T_FAW, T_CK_CTRL) - 1) << 16)),
|
||||
&ctrl->dlycfg3);
|
||||
|
||||
/* ODT Config */
|
||||
writel(0x0, &ctrl->odtcfg);
|
||||
writel(BIT(16), &ctrl->odtencfg);
|
||||
writel(ODTRDLY(RL - 3) | ODTWDLY(WL - 3) | ODTRLEN(2) | ODTWLEN(3),
|
||||
&ctrl->odtcfg);
|
||||
|
||||
/* Transfer Configuration */
|
||||
writel(NXTDATRQDLY(2) | NXDATAVDLY(4) | RDATENDLY(2) |
|
||||
MAX_BURST(3) | (7 << 28) | BIG_ENDIAN(0),
|
||||
&ctrl->xfercfg);
|
||||
|
||||
/* DRAM Initialization */
|
||||
/* CKE high after reset and wait 400 nsec */
|
||||
host_load_cmd(ctrl, 0, 0, IDLE_NOP, 400000);
|
||||
|
||||
/* issue precharge all command */
|
||||
host_load_cmd(ctrl, 1, 0x04, PRECH_ALL_CMD, T_RP + T_CK);
|
||||
|
||||
/* initialize EMR2 */
|
||||
host_load_cmd(ctrl, 2, 0x200, LOAD_MODE_CMD, T_MRD_TCK * T_CK);
|
||||
|
||||
/* initialize EMR3 */
|
||||
host_load_cmd(ctrl, 3, 0x300, LOAD_MODE_CMD, T_MRD_TCK * T_CK);
|
||||
|
||||
/*
|
||||
* RDQS disable, DQSB enable, OCD exit, 150 ohm termination,
|
||||
* AL=0, DLL enable
|
||||
*/
|
||||
host_load_cmd(ctrl, 4, 0x100,
|
||||
LOAD_MODE_CMD | (0x40 << 24), T_MRD_TCK * T_CK);
|
||||
/*
|
||||
* PD fast exit, WR REC = T_WR in clocks -1,
|
||||
* DLL reset, CAS = RL, burst = 4
|
||||
*/
|
||||
temp = ((DIV_ROUND_UP(T_WR, T_CK) - 1) << 1) | 1;
|
||||
host_load_cmd(ctrl, 5, temp, LOAD_MODE_CMD | (RL << 28) | (2 << 24),
|
||||
T_MRD_TCK * T_CK);
|
||||
|
||||
/* issue precharge all command */
|
||||
host_load_cmd(ctrl, 6, 4, PRECH_ALL_CMD, T_RP + T_CK);
|
||||
|
||||
/* issue refresh command */
|
||||
host_load_cmd(ctrl, 7, 0, REF_CMD, T_RFC_MIN);
|
||||
|
||||
/* issue refresh command */
|
||||
host_load_cmd(ctrl, 8, 0, REF_CMD, T_RFC_MIN);
|
||||
|
||||
/* Mode register programming as before without DLL reset */
|
||||
host_load_cmd(ctrl, 9, temp, LOAD_MODE_CMD | (RL << 28) | (3 << 24),
|
||||
T_MRD_TCK * T_CK);
|
||||
|
||||
/* extended mode register same as before with OCD default */
|
||||
host_load_cmd(ctrl, 10, 0x103, LOAD_MODE_CMD | (0xc << 24),
|
||||
T_MRD_TCK * T_CK);
|
||||
|
||||
/* extended mode register same as before with OCD exit */
|
||||
host_load_cmd(ctrl, 11, 0x100, LOAD_MODE_CMD | (0x4 << 28),
|
||||
140 * T_CK);
|
||||
|
||||
writel(CMD_VALID | NUMHOSTCMD(11), &ctrl->cmdissue);
|
||||
|
||||
/* start memory initialization */
|
||||
writel(INIT_START, &ctrl->memcon);
|
||||
|
||||
/* wait for all host cmds to be transmitted */
|
||||
wait_for_bit(__func__, &ctrl->cmdissue, CMD_VALID, false,
|
||||
CONFIG_SYS_HZ, false);
|
||||
|
||||
/* inform all cmds issued, ready for normal operation */
|
||||
writel(INIT_START | INIT_DONE, &ctrl->memcon);
|
||||
|
||||
/* perform phy caliberation */
|
||||
if (ddr2_phy_calib_start())
|
||||
printf("ddr2: phy calib failed\n");
|
||||
}
|
||||
|
||||
phys_size_t ddr2_calculate_size(void)
|
||||
{
|
||||
u32 temp;
|
||||
|
||||
temp = 1 << (COL_BITS + BA_BITS + ROW_BITS);
|
||||
/* 16-bit data width between controller and DIMM */
|
||||
temp = temp * CS_BITS * (16 / 8);
|
||||
return (phys_size_t)temp;
|
||||
}
|
148
drivers/ddr/microchip/ddr2_regs.h
Normal file
148
drivers/ddr/microchip/ddr2_regs.h
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* (c) 2015 Purna Chandra Mandal <purna.mandal@microchip.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MICROCHIP_DDR2_REGS_H
|
||||
#define __MICROCHIP_DDR2_REGS_H
|
||||
|
||||
#include <linux/bitops.h>
|
||||
|
||||
/* DDR2 Controller */
|
||||
struct ddr2_ctrl_regs {
|
||||
u32 tsel;
|
||||
u32 minlim;
|
||||
u32 reqprd;
|
||||
u32 mincmd;
|
||||
u32 memcon;
|
||||
u32 memcfg0;
|
||||
u32 memcfg1;
|
||||
u32 memcfg2;
|
||||
u32 memcfg3;
|
||||
u32 memcfg4;
|
||||
u32 refcfg;
|
||||
u32 pwrcfg;
|
||||
u32 dlycfg0;
|
||||
u32 dlycfg1;
|
||||
u32 dlycfg2;
|
||||
u32 dlycfg3;
|
||||
u32 odtcfg;
|
||||
u32 xfercfg;
|
||||
u32 cmdissue;
|
||||
u32 odtencfg;
|
||||
u32 memwidth;
|
||||
u32 unused[11];
|
||||
u32 cmd10[16];
|
||||
u32 cmd20[16];
|
||||
};
|
||||
|
||||
/* Arbiter Config */
|
||||
#define MIN_LIM_WIDTH 5
|
||||
#define RQST_PERIOD_WIDTH 8
|
||||
#define MIN_CMDACPT_WIDTH 8
|
||||
|
||||
/* Refresh Config */
|
||||
#define REFCNT_CLK(x) (x)
|
||||
#define REFDLY_CLK(x) ((x) << 16)
|
||||
#define MAX_PEND_REF(x) ((x) << 24)
|
||||
|
||||
/* Power Config */
|
||||
#define PRECH_PWR_DN_ONLY(x) ((x) << 22)
|
||||
#define SELF_REF_DLY(x) ((x) << 12)
|
||||
#define PWR_DN_DLY(x) ((x) << 4)
|
||||
#define EN_AUTO_SELF_REF(x) ((x) << 3)
|
||||
#define EN_AUTO_PWR_DN(x) ((x) << 2)
|
||||
#define ERR_CORR_EN(x) ((x) << 1)
|
||||
#define ECC_EN(x) (x)
|
||||
|
||||
/* Memory Width */
|
||||
#define HALF_RATE_MODE BIT(3)
|
||||
|
||||
/* Delay Config */
|
||||
#define ODTWLEN(x) ((x) << 20)
|
||||
#define ODTRLEN(x) ((x) << 16)
|
||||
#define ODTWDLY(x) ((x) << 12)
|
||||
#define ODTRDLY(x) ((x) << 8)
|
||||
|
||||
/* Xfer Config */
|
||||
#define BIG_ENDIAN(x) ((x) << 31)
|
||||
#define MAX_BURST(x) ((x) << 24)
|
||||
#define RDATENDLY(x) ((x) << 16)
|
||||
#define NXDATAVDLY(x) ((x) << 4)
|
||||
#define NXTDATRQDLY(x) ((x) << 0)
|
||||
|
||||
/* Host Commands */
|
||||
#define IDLE_NOP 0x00ffffff
|
||||
#define PRECH_ALL_CMD 0x00fff401
|
||||
#define REF_CMD 0x00fff801
|
||||
#define LOAD_MODE_CMD 0x00fff001
|
||||
#define CKE_LOW 0x00ffeffe
|
||||
|
||||
#define NUM_HOST_CMDS 12
|
||||
|
||||
/* Host CMD Issue */
|
||||
#define CMD_VALID BIT(4)
|
||||
#define NUMHOSTCMD(x) (x)
|
||||
|
||||
/* Memory Control */
|
||||
#define INIT_DONE BIT(1)
|
||||
#define INIT_START BIT(0)
|
||||
|
||||
/* Address Control */
|
||||
#define EN_AUTO_PRECH 0
|
||||
#define SB_PRI 1
|
||||
|
||||
/* DDR2 Phy Register */
|
||||
struct ddr2_phy_regs {
|
||||
u32 scl_start;
|
||||
u32 unused1[2];
|
||||
u32 scl_latency;
|
||||
u32 unused2[2];
|
||||
u32 scl_config_1;
|
||||
u32 scl_config_2;
|
||||
u32 pad_ctrl;
|
||||
u32 dll_recalib;
|
||||
};
|
||||
|
||||
/* PHY PAD CONTROL */
|
||||
#define ODT_SEL BIT(0)
|
||||
#define ODT_EN BIT(1)
|
||||
#define DRIVE_SEL(x) ((x) << 2)
|
||||
#define ODT_PULLDOWN(x) ((x) << 4)
|
||||
#define ODT_PULLUP(x) ((x) << 6)
|
||||
#define EXTRA_OEN_CLK(x) ((x) << 8)
|
||||
#define NOEXT_DLL BIT(9)
|
||||
#define DLR_DFT_WRCMD BIT(13)
|
||||
#define HALF_RATE BIT(14)
|
||||
#define DRVSTR_PFET(x) ((x) << 16)
|
||||
#define DRVSTR_NFET(x) ((x) << 20)
|
||||
#define RCVR_EN BIT(28)
|
||||
#define PREAMBLE_DLY(x) ((x) << 29)
|
||||
|
||||
/* PHY DLL RECALIBRATE */
|
||||
#define RECALIB_CNT(x) ((x) << 8)
|
||||
#define DISABLE_RECALIB(x) ((x) << 26)
|
||||
#define DELAY_START_VAL(x) ((x) << 28)
|
||||
|
||||
/* PHY SCL CONFIG1 */
|
||||
#define SCL_BURST8 BIT(0)
|
||||
#define SCL_DDR_CONNECTED BIT(1)
|
||||
#define SCL_RCAS_LAT(x) ((x) << 4)
|
||||
#define SCL_ODTCSWW BIT(24)
|
||||
|
||||
/* PHY SCL CONFIG2 */
|
||||
#define SCL_CSEN BIT(0)
|
||||
#define SCL_WCAS_LAT(x) ((x) << 8)
|
||||
|
||||
/* PHY SCL Latency */
|
||||
#define SCL_CAPCLKDLY(x) ((x) << 0)
|
||||
#define SCL_DDRCLKDLY(x) ((x) << 4)
|
||||
|
||||
/* PHY SCL START */
|
||||
#define SCL_START BIT(28)
|
||||
#define SCL_EN BIT(26)
|
||||
#define SCL_LUBPASS (BIT(1) | BIT(0))
|
||||
|
||||
#endif /* __MICROCHIP_DDR2_REGS_H */
|
65
drivers/ddr/microchip/ddr2_timing.h
Normal file
65
drivers/ddr/microchip/ddr2_timing.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* (c) 2015 Purna Chandra Mandal <purna.mandal@microchip.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MICROCHIP_DDR2_TIMING_H
|
||||
#define __MICROCHIP_DDR2_TIMING_H
|
||||
|
||||
/* MPLL freq is 400MHz */
|
||||
#define T_CK 2500 /* 2500 psec */
|
||||
#define T_CK_CTRL (T_CK * 2)
|
||||
|
||||
/* Burst length in cycles */
|
||||
#define BL 2
|
||||
/* default CAS latency for all speed grades */
|
||||
#define RL 5
|
||||
/* default write latency for all speed grades = CL-1 */
|
||||
#define WL 4
|
||||
|
||||
/* From Micron MT47H64M16HR-3 data sheet */
|
||||
#define T_RFC_MIN 127500 /* psec */
|
||||
#define T_WR 15000 /* psec */
|
||||
#define T_RP 12500 /* psec */
|
||||
#define T_RCD 12500 /* psec */
|
||||
#define T_RRD 7500 /* psec */
|
||||
/* T_RRD_TCK is minimum of 2 clk periods, regardless of freq */
|
||||
#define T_RRD_TCK 2
|
||||
#define T_WTR 7500 /* psec */
|
||||
/* T_WTR_TCK is minimum of 2 clk periods, regardless of freq */
|
||||
#define T_WTR_TCK 2
|
||||
#define T_RTP 7500 /* psec */
|
||||
#define T_RTP_TCK (BL / 2)
|
||||
#define T_XP_TCK 2 /* clocks */
|
||||
#define T_CKE_TCK 3 /* clocks */
|
||||
#define T_XSNR (T_RFC_MIN + 10000) /* psec */
|
||||
#define T_DLLK 200 /* clocks */
|
||||
#define T_RAS_MIN 45000 /* psec */
|
||||
#define T_RC 57500 /* psec */
|
||||
#define T_FAW 35000 /* psec */
|
||||
#define T_MRD_TCK 2 /* clocks */
|
||||
#define T_RFI 7800000 /* psec */
|
||||
|
||||
/* DDR Addressing */
|
||||
#define COL_BITS 10
|
||||
#define BA_BITS 3
|
||||
#define ROW_BITS 13
|
||||
#define CS_BITS 1
|
||||
|
||||
/* DDR Addressing scheme: {CS, ROW, BA, COL} */
|
||||
#define COL_HI_RSHFT 0
|
||||
#define COL_HI_MASK 0
|
||||
#define COL_LO_MASK ((1 << COL_BITS) - 1)
|
||||
|
||||
#define BA_RSHFT COL_BITS
|
||||
#define BA_MASK ((1 << BA_BITS) - 1)
|
||||
|
||||
#define ROW_ADDR_RSHIFT (BA_RSHFT + BA_BITS)
|
||||
#define ROW_ADDR_MASK ((1 << ROW_BITS) - 1)
|
||||
|
||||
#define CS_ADDR_RSHIFT 0
|
||||
#define CS_ADDR_MASK 0
|
||||
|
||||
#endif /* __MICROCHIP_DDR2_TIMING_H */
|
|
@ -83,4 +83,11 @@ config VYBRID_GPIO
|
|||
help
|
||||
Say yes here to support Vybrid vf610 GPIOs.
|
||||
|
||||
config PIC32_GPIO
|
||||
bool "Microchip PIC32 GPIO driver"
|
||||
depends on DM_GPIO && MACH_PIC32
|
||||
default y
|
||||
help
|
||||
Say yes here to support Microchip PIC32 GPIOs.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -46,4 +46,4 @@ obj-$(CONFIG_STM32_GPIO) += stm32_gpio.o
|
|||
obj-$(CONFIG_ZYNQ_GPIO) += zynq_gpio.o
|
||||
obj-$(CONFIG_VYBRID_GPIO) += vybrid_gpio.o
|
||||
obj-$(CONFIG_HIKEY_GPIO) += hi6220_gpio.o
|
||||
|
||||
obj-$(CONFIG_PIC32_GPIO) += pic32_gpio.o
|
||||
|
|
174
drivers/gpio/pic32_gpio.c
Normal file
174
drivers/gpio/pic32_gpio.c
Normal file
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Microchip Technology Inc
|
||||
* Purna Chandra Mandal <purna.mandal@microchip.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <linux/compat.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <mach/pic32.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/* Peripheral Pin Control */
|
||||
struct pic32_reg_port {
|
||||
struct pic32_reg_atomic ansel;
|
||||
struct pic32_reg_atomic tris;
|
||||
struct pic32_reg_atomic port;
|
||||
struct pic32_reg_atomic lat;
|
||||
struct pic32_reg_atomic open_drain;
|
||||
struct pic32_reg_atomic cnpu;
|
||||
struct pic32_reg_atomic cnpd;
|
||||
struct pic32_reg_atomic cncon;
|
||||
};
|
||||
|
||||
enum {
|
||||
MICROCHIP_GPIO_DIR_OUT,
|
||||
MICROCHIP_GPIO_DIR_IN,
|
||||
MICROCHIP_GPIOS_PER_BANK = 16,
|
||||
};
|
||||
|
||||
struct pic32_gpio_priv {
|
||||
struct pic32_reg_port *regs;
|
||||
char name[2];
|
||||
};
|
||||
|
||||
static int pic32_gpio_get_value(struct udevice *dev, unsigned offset)
|
||||
{
|
||||
struct pic32_gpio_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return !!(readl(&priv->regs->port.raw) & BIT(offset));
|
||||
}
|
||||
|
||||
static int pic32_gpio_set_value(struct udevice *dev, unsigned offset,
|
||||
int value)
|
||||
{
|
||||
struct pic32_gpio_priv *priv = dev_get_priv(dev);
|
||||
int mask = BIT(offset);
|
||||
|
||||
if (value)
|
||||
writel(mask, &priv->regs->port.set);
|
||||
else
|
||||
writel(mask, &priv->regs->port.clr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pic32_gpio_direction(struct udevice *dev, unsigned offset)
|
||||
{
|
||||
struct pic32_gpio_priv *priv = dev_get_priv(dev);
|
||||
|
||||
/* pin in analog mode ? */
|
||||
if (readl(&priv->regs->ansel.raw) & BIT(offset))
|
||||
return -EPERM;
|
||||
|
||||
if (readl(&priv->regs->tris.raw) & BIT(offset))
|
||||
return MICROCHIP_GPIO_DIR_IN;
|
||||
else
|
||||
return MICROCHIP_GPIO_DIR_OUT;
|
||||
}
|
||||
|
||||
static int pic32_gpio_direction_input(struct udevice *dev, unsigned offset)
|
||||
{
|
||||
struct pic32_gpio_priv *priv = dev_get_priv(dev);
|
||||
int mask = BIT(offset);
|
||||
|
||||
writel(mask, &priv->regs->ansel.clr);
|
||||
writel(mask, &priv->regs->tris.set);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pic32_gpio_direction_output(struct udevice *dev,
|
||||
unsigned offset, int value)
|
||||
{
|
||||
struct pic32_gpio_priv *priv = dev_get_priv(dev);
|
||||
int mask = BIT(offset);
|
||||
|
||||
writel(mask, &priv->regs->ansel.clr);
|
||||
writel(mask, &priv->regs->tris.clr);
|
||||
|
||||
pic32_gpio_set_value(dev, offset, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pic32_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
|
||||
struct fdtdec_phandle_args *args)
|
||||
{
|
||||
desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pic32_gpio_get_function(struct udevice *dev, unsigned offset)
|
||||
{
|
||||
int ret = GPIOF_UNUSED;
|
||||
|
||||
switch (pic32_gpio_direction(dev, offset)) {
|
||||
case MICROCHIP_GPIO_DIR_OUT:
|
||||
ret = GPIOF_OUTPUT;
|
||||
break;
|
||||
case MICROCHIP_GPIO_DIR_IN:
|
||||
ret = GPIOF_INPUT;
|
||||
break;
|
||||
default:
|
||||
ret = GPIOF_UNUSED;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dm_gpio_ops gpio_pic32_ops = {
|
||||
.direction_input = pic32_gpio_direction_input,
|
||||
.direction_output = pic32_gpio_direction_output,
|
||||
.get_value = pic32_gpio_get_value,
|
||||
.set_value = pic32_gpio_set_value,
|
||||
.get_function = pic32_gpio_get_function,
|
||||
.xlate = pic32_gpio_xlate,
|
||||
};
|
||||
|
||||
static int pic32_gpio_probe(struct udevice *dev)
|
||||
{
|
||||
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
struct pic32_gpio_priv *priv = dev_get_priv(dev);
|
||||
fdt_addr_t addr;
|
||||
fdt_size_t size;
|
||||
char *end;
|
||||
int bank;
|
||||
|
||||
addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg", &size);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
priv->regs = ioremap(addr, size);
|
||||
|
||||
uc_priv->gpio_count = MICROCHIP_GPIOS_PER_BANK;
|
||||
/* extract bank name */
|
||||
end = strrchr(dev->name, '@');
|
||||
bank = trailing_strtoln(dev->name, end);
|
||||
priv->name[0] = 'A' + bank;
|
||||
uc_priv->bank_name = priv->name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id pic32_gpio_ids[] = {
|
||||
{ .compatible = "microchip,pic32mzda-gpio" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(gpio_pic32) = {
|
||||
.name = "gpio_pic32",
|
||||
.id = UCLASS_GPIO,
|
||||
.of_match = pic32_gpio_ids,
|
||||
.ops = &gpio_pic32_ops,
|
||||
.probe = pic32_gpio_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct pic32_gpio_priv),
|
||||
};
|
|
@ -31,4 +31,10 @@ config SH_SDHI
|
|||
help
|
||||
Support for the on-chip SDHI host controller on SuperH/Renesas ARM SoCs platform
|
||||
|
||||
config PIC32_SDHCI
|
||||
bool "Microchip PIC32 on-chip SDHCI support"
|
||||
depends on DM_MMC && MACH_PIC32
|
||||
help
|
||||
Support for Microchip PIC32 SDHCI controller.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -48,4 +48,4 @@ obj-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o
|
|||
else
|
||||
obj-$(CONFIG_GENERIC_MMC) += mmc_write.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_PIC32_SDHCI) += pic32_sdhci.o
|
||||
|
|
58
drivers/mmc/pic32_sdhci.c
Normal file
58
drivers/mmc/pic32_sdhci.c
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Support of SDHCI for Microchip PIC32 SoC.
|
||||
*
|
||||
* Copyright (C) 2015 Microchip Technology Inc.
|
||||
* Andrei Pistirica <andrei.pistirica@microchip.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <dm.h>
|
||||
#include <common.h>
|
||||
#include <sdhci.h>
|
||||
#include <asm/errno.h>
|
||||
#include <mach/pic32.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static int pic32_sdhci_probe(struct udevice *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_priv(dev);
|
||||
const void *fdt = gd->fdt_blob;
|
||||
u32 f_min_max[2];
|
||||
fdt_addr_t addr;
|
||||
fdt_size_t size;
|
||||
int ret;
|
||||
|
||||
addr = fdtdec_get_addr_size(fdt, dev->of_offset, "reg", &size);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
host->ioaddr = ioremap(addr, size);
|
||||
host->name = (char *)dev->name;
|
||||
host->quirks = SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_NO_CD;
|
||||
host->bus_width = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
|
||||
"bus-width", 4);
|
||||
|
||||
ret = fdtdec_get_int_array(gd->fdt_blob, dev->of_offset,
|
||||
"clock-freq-min-max", f_min_max, 2);
|
||||
if (ret) {
|
||||
printf("sdhci: clock-freq-min-max not found\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return add_sdhci(host, f_min_max[1], f_min_max[0]);
|
||||
}
|
||||
|
||||
static const struct udevice_id pic32_sdhci_ids[] = {
|
||||
{ .compatible = "microchip,pic32mzda-sdhci" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(pic32_sdhci_drv) = {
|
||||
.name = "pic32_sdhci",
|
||||
.id = UCLASS_MMC,
|
||||
.of_match = pic32_sdhci_ids,
|
||||
.probe = pic32_sdhci_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct sdhci_host),
|
||||
};
|
|
@ -443,6 +443,12 @@ static int sdhci_init(struct mmc *mmc)
|
|||
sdhci_set_power(host, fls(mmc->cfg->voltages) - 1);
|
||||
|
||||
if (host->quirks & SDHCI_QUIRK_NO_CD) {
|
||||
#if defined(CONFIG_PIC32_SDHCI)
|
||||
/* PIC32 SDHCI CD errata:
|
||||
* - set CD_TEST and clear CD_TEST_INS bit
|
||||
*/
|
||||
sdhci_writeb(host, SDHCI_CTRL_CD_TEST, SDHCI_HOST_CONTROL);
|
||||
#else
|
||||
unsigned int status;
|
||||
|
||||
sdhci_writeb(host, SDHCI_CTRL_CD_TEST_INS | SDHCI_CTRL_CD_TEST,
|
||||
|
@ -453,6 +459,7 @@ static int sdhci_init(struct mmc *mmc)
|
|||
(!(status & SDHCI_CARD_STATE_STABLE)) ||
|
||||
(!(status & SDHCI_CARD_DETECT_PIN_LEVEL)))
|
||||
status = sdhci_readl(host, SDHCI_PRESENT_STATE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Enable only interrupts served by the SD controller */
|
||||
|
|
|
@ -125,4 +125,12 @@ config ZYNQ_GEM
|
|||
help
|
||||
This MAC is present in Xilinx Zynq and ZynqMP SoCs.
|
||||
|
||||
config PIC32_ETH
|
||||
bool "Microchip PIC32 Ethernet Support"
|
||||
depends on DM_ETH && MACH_PIC32
|
||||
select PHYLIB
|
||||
help
|
||||
This driver implements 10/100 Mbps Ethernet and MAC layer for
|
||||
Microchip PIC32 microcontrollers.
|
||||
|
||||
endif # NETDEVICES
|
||||
|
|
|
@ -72,3 +72,4 @@ obj-$(CONFIG_FSL_MC_ENET) += fsl-mc/
|
|||
obj-$(CONFIG_FSL_MC_ENET) += ldpaa_eth/
|
||||
obj-$(CONFIG_FSL_MEMAC) += fm/memac_phy.o
|
||||
obj-$(CONFIG_VSC9953) += vsc9953.o
|
||||
obj-$(CONFIG_PIC32_ETH) += pic32_mdio.o pic32_eth.o
|
||||
|
|
|
@ -69,11 +69,21 @@ static struct phy_driver lan8710_driver = {
|
|||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
static struct phy_driver lan8740_driver = {
|
||||
.name = "SMSC LAN8740",
|
||||
.uid = 0x0007c110,
|
||||
.mask = 0xffff0,
|
||||
.features = PHY_BASIC_FEATURES,
|
||||
.config = &genphy_config_aneg,
|
||||
.startup = &genphy_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
int phy_smsc_init(void)
|
||||
{
|
||||
phy_register(&lan8710_driver);
|
||||
phy_register(&lan911x_driver);
|
||||
phy_register(&lan8700_driver);
|
||||
phy_register(&lan8740_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
605
drivers/net/pic32_eth.c
Normal file
605
drivers/net/pic32_eth.c
Normal file
|
@ -0,0 +1,605 @@
|
|||
/*
|
||||
* (c) 2015 Purna Chandra Mandal <purna.mandal@microchip.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <dm.h>
|
||||
#include <net.h>
|
||||
#include <miiphy.h>
|
||||
#include <console.h>
|
||||
#include <wait_bit.h>
|
||||
#include <asm/gpio.h>
|
||||
|
||||
#include "pic32_eth.h"
|
||||
|
||||
#define MAX_RX_BUF_SIZE 1536
|
||||
#define MAX_RX_DESCR PKTBUFSRX
|
||||
#define MAX_TX_DESCR 2
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
struct pic32eth_dev {
|
||||
struct eth_dma_desc rxd_ring[MAX_RX_DESCR];
|
||||
struct eth_dma_desc txd_ring[MAX_TX_DESCR];
|
||||
u32 rxd_idx; /* index of RX desc to read */
|
||||
/* regs */
|
||||
struct pic32_ectl_regs *ectl_regs;
|
||||
struct pic32_emac_regs *emac_regs;
|
||||
/* Phy */
|
||||
struct phy_device *phydev;
|
||||
phy_interface_t phyif;
|
||||
u32 phy_addr;
|
||||
struct gpio_desc rst_gpio;
|
||||
};
|
||||
|
||||
void __weak board_netphy_reset(void *dev)
|
||||
{
|
||||
struct pic32eth_dev *priv = dev;
|
||||
|
||||
if (!dm_gpio_is_valid(&priv->rst_gpio))
|
||||
return;
|
||||
|
||||
/* phy reset */
|
||||
dm_gpio_set_value(&priv->rst_gpio, 0);
|
||||
udelay(300);
|
||||
dm_gpio_set_value(&priv->rst_gpio, 1);
|
||||
udelay(300);
|
||||
}
|
||||
|
||||
/* Initialize mii(MDIO) interface, discover which PHY is
|
||||
* attached to the device, and configure it properly.
|
||||
*/
|
||||
static int pic32_mii_init(struct pic32eth_dev *priv)
|
||||
{
|
||||
struct pic32_ectl_regs *ectl_p = priv->ectl_regs;
|
||||
struct pic32_emac_regs *emac_p = priv->emac_regs;
|
||||
|
||||
/* board phy reset */
|
||||
board_netphy_reset(priv);
|
||||
|
||||
/* disable RX, TX & all transactions */
|
||||
writel(ETHCON_ON | ETHCON_TXRTS | ETHCON_RXEN, &ectl_p->con1.clr);
|
||||
|
||||
/* wait till busy */
|
||||
wait_for_bit(__func__, &ectl_p->stat.raw, ETHSTAT_BUSY, false,
|
||||
CONFIG_SYS_HZ, false);
|
||||
|
||||
/* turn controller ON to access PHY over MII */
|
||||
writel(ETHCON_ON, &ectl_p->con1.set);
|
||||
|
||||
mdelay(10);
|
||||
|
||||
/* reset MAC */
|
||||
writel(EMAC_SOFTRESET, &emac_p->cfg1.set); /* reset assert */
|
||||
mdelay(10);
|
||||
writel(EMAC_SOFTRESET, &emac_p->cfg1.clr); /* reset deassert */
|
||||
|
||||
/* initialize MDIO/MII */
|
||||
if (priv->phyif == PHY_INTERFACE_MODE_RMII) {
|
||||
writel(EMAC_RMII_RESET, &emac_p->supp.set);
|
||||
mdelay(10);
|
||||
writel(EMAC_RMII_RESET, &emac_p->supp.clr);
|
||||
}
|
||||
|
||||
return pic32_mdio_init(PIC32_MDIO_NAME, (ulong)&emac_p->mii);
|
||||
}
|
||||
|
||||
static int pic32_phy_init(struct pic32eth_dev *priv, struct udevice *dev)
|
||||
{
|
||||
struct mii_dev *mii;
|
||||
|
||||
mii = miiphy_get_dev_by_name(PIC32_MDIO_NAME);
|
||||
|
||||
/* find & connect PHY */
|
||||
priv->phydev = phy_connect(mii, priv->phy_addr,
|
||||
dev, priv->phyif);
|
||||
if (!priv->phydev) {
|
||||
printf("%s: %s: Error, PHY connect\n", __FILE__, __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Wait for phy to complete reset */
|
||||
mdelay(10);
|
||||
|
||||
/* configure supported modes */
|
||||
priv->phydev->supported = SUPPORTED_10baseT_Half |
|
||||
SUPPORTED_10baseT_Full |
|
||||
SUPPORTED_100baseT_Half |
|
||||
SUPPORTED_100baseT_Full |
|
||||
SUPPORTED_Autoneg;
|
||||
|
||||
priv->phydev->advertising = ADVERTISED_10baseT_Half |
|
||||
ADVERTISED_10baseT_Full |
|
||||
ADVERTISED_100baseT_Half |
|
||||
ADVERTISED_100baseT_Full |
|
||||
ADVERTISED_Autoneg;
|
||||
|
||||
priv->phydev->autoneg = AUTONEG_ENABLE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Configure MAC based on negotiated speed and duplex
|
||||
* reported by PHY.
|
||||
*/
|
||||
static int pic32_mac_adjust_link(struct pic32eth_dev *priv)
|
||||
{
|
||||
struct phy_device *phydev = priv->phydev;
|
||||
struct pic32_emac_regs *emac_p = priv->emac_regs;
|
||||
|
||||
if (!phydev->link) {
|
||||
printf("%s: No link.\n", phydev->dev->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (phydev->duplex) {
|
||||
writel(EMAC_FULLDUP, &emac_p->cfg2.set);
|
||||
writel(FULLDUP_GAP_TIME, &emac_p->ipgt.raw);
|
||||
} else {
|
||||
writel(EMAC_FULLDUP, &emac_p->cfg2.clr);
|
||||
writel(HALFDUP_GAP_TIME, &emac_p->ipgt.raw);
|
||||
}
|
||||
|
||||
switch (phydev->speed) {
|
||||
case SPEED_100:
|
||||
writel(EMAC_RMII_SPD100, &emac_p->supp.set);
|
||||
break;
|
||||
case SPEED_10:
|
||||
writel(EMAC_RMII_SPD100, &emac_p->supp.clr);
|
||||
break;
|
||||
default:
|
||||
printf("%s: Speed was bad\n", phydev->dev->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
printf("pic32eth: PHY is %s with %dbase%s, %s\n",
|
||||
phydev->drv->name, phydev->speed,
|
||||
(phydev->port == PORT_TP) ? "T" : "X",
|
||||
(phydev->duplex) ? "full" : "half");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pic32_mac_init(struct pic32eth_dev *priv, u8 *macaddr)
|
||||
{
|
||||
struct pic32_emac_regs *emac_p = priv->emac_regs;
|
||||
u32 stat = 0, v;
|
||||
u64 expire;
|
||||
|
||||
v = EMAC_TXPAUSE | EMAC_RXPAUSE | EMAC_RXENABLE;
|
||||
writel(v, &emac_p->cfg1.raw);
|
||||
|
||||
v = EMAC_EXCESS | EMAC_AUTOPAD | EMAC_PADENABLE |
|
||||
EMAC_CRCENABLE | EMAC_LENGTHCK | EMAC_FULLDUP;
|
||||
writel(v, &emac_p->cfg2.raw);
|
||||
|
||||
/* recommended back-to-back inter-packet gap for 10 Mbps half duplex */
|
||||
writel(HALFDUP_GAP_TIME, &emac_p->ipgt.raw);
|
||||
|
||||
/* recommended non-back-to-back interpacket gap is 0xc12 */
|
||||
writel(0xc12, &emac_p->ipgr.raw);
|
||||
|
||||
/* recommended collision window retry limit is 0x370F */
|
||||
writel(0x370f, &emac_p->clrt.raw);
|
||||
|
||||
/* set maximum frame length: allow VLAN tagged frame */
|
||||
writel(0x600, &emac_p->maxf.raw);
|
||||
|
||||
/* set the mac address */
|
||||
writel(macaddr[0] | (macaddr[1] << 8), &emac_p->sa2.raw);
|
||||
writel(macaddr[2] | (macaddr[3] << 8), &emac_p->sa1.raw);
|
||||
writel(macaddr[4] | (macaddr[5] << 8), &emac_p->sa0.raw);
|
||||
|
||||
/* default, enable 10 Mbps operation */
|
||||
writel(EMAC_RMII_SPD100, &emac_p->supp.clr);
|
||||
|
||||
/* wait until link status UP or deadline elapsed */
|
||||
expire = get_ticks() + get_tbclk() * 2;
|
||||
for (; get_ticks() < expire;) {
|
||||
stat = phy_read(priv->phydev, priv->phy_addr, MII_BMSR);
|
||||
if (stat & BMSR_LSTATUS)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(stat & BMSR_LSTATUS))
|
||||
printf("MAC: Link is DOWN!\n");
|
||||
|
||||
/* delay to stabilize before any tx/rx */
|
||||
mdelay(10);
|
||||
}
|
||||
|
||||
static void pic32_mac_reset(struct pic32eth_dev *priv)
|
||||
{
|
||||
struct pic32_emac_regs *emac_p = priv->emac_regs;
|
||||
struct mii_dev *mii;
|
||||
|
||||
/* Reset MAC */
|
||||
writel(EMAC_SOFTRESET, &emac_p->cfg1.raw);
|
||||
mdelay(10);
|
||||
|
||||
/* clear reset */
|
||||
writel(0, &emac_p->cfg1.raw);
|
||||
|
||||
/* Reset MII */
|
||||
mii = priv->phydev->bus;
|
||||
if (mii && mii->reset)
|
||||
mii->reset(mii);
|
||||
}
|
||||
|
||||
/* initializes the MAC and PHY, then establishes a link */
|
||||
static void pic32_ctrl_reset(struct pic32eth_dev *priv)
|
||||
{
|
||||
struct pic32_ectl_regs *ectl_p = priv->ectl_regs;
|
||||
u32 v;
|
||||
|
||||
/* disable RX, TX & any other transactions */
|
||||
writel(ETHCON_ON | ETHCON_TXRTS | ETHCON_RXEN, &ectl_p->con1.clr);
|
||||
|
||||
/* wait till busy */
|
||||
wait_for_bit(__func__, &ectl_p->stat.raw, ETHSTAT_BUSY, false,
|
||||
CONFIG_SYS_HZ, false);
|
||||
/* decrement received buffcnt to zero. */
|
||||
while (readl(&ectl_p->stat.raw) & ETHSTAT_BUFCNT)
|
||||
writel(ETHCON_BUFCDEC, &ectl_p->con1.set);
|
||||
|
||||
/* clear any existing interrupt event */
|
||||
writel(0xffffffff, &ectl_p->irq.clr);
|
||||
|
||||
/* clear RX/TX start address */
|
||||
writel(0xffffffff, &ectl_p->txst.clr);
|
||||
writel(0xffffffff, &ectl_p->rxst.clr);
|
||||
|
||||
/* clear the receive filters */
|
||||
writel(0x00ff, &ectl_p->rxfc.clr);
|
||||
|
||||
/* set the receive filters
|
||||
* ETH_FILT_CRC_ERR_REJECT
|
||||
* ETH_FILT_RUNT_REJECT
|
||||
* ETH_FILT_UCAST_ACCEPT
|
||||
* ETH_FILT_MCAST_ACCEPT
|
||||
* ETH_FILT_BCAST_ACCEPT
|
||||
*/
|
||||
v = ETHRXFC_BCEN | ETHRXFC_MCEN | ETHRXFC_UCEN |
|
||||
ETHRXFC_RUNTEN | ETHRXFC_CRCOKEN;
|
||||
writel(v, &ectl_p->rxfc.set);
|
||||
|
||||
/* turn controller ON to access PHY over MII */
|
||||
writel(ETHCON_ON, &ectl_p->con1.set);
|
||||
}
|
||||
|
||||
static void pic32_rx_desc_init(struct pic32eth_dev *priv)
|
||||
{
|
||||
struct pic32_ectl_regs *ectl_p = priv->ectl_regs;
|
||||
struct eth_dma_desc *rxd;
|
||||
u32 idx, bufsz;
|
||||
|
||||
priv->rxd_idx = 0;
|
||||
for (idx = 0; idx < MAX_RX_DESCR; idx++) {
|
||||
rxd = &priv->rxd_ring[idx];
|
||||
|
||||
/* hw owned */
|
||||
rxd->hdr = EDH_NPV | EDH_EOWN | EDH_STICKY;
|
||||
|
||||
/* packet buffer address */
|
||||
rxd->data_buff = virt_to_phys(net_rx_packets[idx]);
|
||||
|
||||
/* link to next desc */
|
||||
rxd->next_ed = virt_to_phys(rxd + 1);
|
||||
|
||||
/* reset status */
|
||||
rxd->stat1 = 0;
|
||||
rxd->stat2 = 0;
|
||||
|
||||
/* decrement bufcnt */
|
||||
writel(ETHCON_BUFCDEC, &ectl_p->con1.set);
|
||||
}
|
||||
|
||||
/* link last descr to beginning of list */
|
||||
rxd->next_ed = virt_to_phys(&priv->rxd_ring[0]);
|
||||
|
||||
/* flush rx ring */
|
||||
flush_dcache_range((ulong)priv->rxd_ring,
|
||||
(ulong)priv->rxd_ring + sizeof(priv->rxd_ring));
|
||||
|
||||
/* set rx desc-ring start address */
|
||||
writel((ulong)virt_to_phys(&priv->rxd_ring[0]), &ectl_p->rxst.raw);
|
||||
|
||||
/* RX Buffer size */
|
||||
bufsz = readl(&ectl_p->con2.raw);
|
||||
bufsz &= ~(ETHCON_RXBUFSZ << ETHCON_RXBUFSZ_SHFT);
|
||||
bufsz |= ((MAX_RX_BUF_SIZE / 16) << ETHCON_RXBUFSZ_SHFT);
|
||||
writel(bufsz, &ectl_p->con2.raw);
|
||||
|
||||
/* enable the receiver in hardware which allows hardware
|
||||
* to DMA received pkts to the descriptor pointer address.
|
||||
*/
|
||||
writel(ETHCON_RXEN, &ectl_p->con1.set);
|
||||
}
|
||||
|
||||
static int pic32_eth_start(struct udevice *dev)
|
||||
{
|
||||
struct eth_pdata *pdata = dev_get_platdata(dev);
|
||||
struct pic32eth_dev *priv = dev_get_priv(dev);
|
||||
|
||||
/* controller */
|
||||
pic32_ctrl_reset(priv);
|
||||
|
||||
/* reset MAC */
|
||||
pic32_mac_reset(priv);
|
||||
|
||||
/* configure PHY */
|
||||
phy_config(priv->phydev);
|
||||
|
||||
/* initialize MAC */
|
||||
pic32_mac_init(priv, &pdata->enetaddr[0]);
|
||||
|
||||
/* init RX descriptor; TX descriptors are handled in xmit */
|
||||
pic32_rx_desc_init(priv);
|
||||
|
||||
/* Start up & update link status of PHY */
|
||||
phy_startup(priv->phydev);
|
||||
|
||||
/* adjust mac with phy link status */
|
||||
return pic32_mac_adjust_link(priv);
|
||||
}
|
||||
|
||||
static void pic32_eth_stop(struct udevice *dev)
|
||||
{
|
||||
struct pic32eth_dev *priv = dev_get_priv(dev);
|
||||
struct pic32_ectl_regs *ectl_p = priv->ectl_regs;
|
||||
struct pic32_emac_regs *emac_p = priv->emac_regs;
|
||||
|
||||
/* Reset the phy if the controller is enabled */
|
||||
if (readl(&ectl_p->con1.raw) & ETHCON_ON)
|
||||
phy_reset(priv->phydev);
|
||||
|
||||
/* Shut down the PHY */
|
||||
phy_shutdown(priv->phydev);
|
||||
|
||||
/* Stop rx/tx */
|
||||
writel(ETHCON_TXRTS | ETHCON_RXEN, &ectl_p->con1.clr);
|
||||
mdelay(10);
|
||||
|
||||
/* reset MAC */
|
||||
writel(EMAC_SOFTRESET, &emac_p->cfg1.raw);
|
||||
|
||||
/* clear reset */
|
||||
writel(0, &emac_p->cfg1.raw);
|
||||
mdelay(10);
|
||||
|
||||
/* disable controller */
|
||||
writel(ETHCON_ON, &ectl_p->con1.clr);
|
||||
mdelay(10);
|
||||
|
||||
/* wait until everything is down */
|
||||
wait_for_bit(__func__, &ectl_p->stat.raw, ETHSTAT_BUSY, false,
|
||||
2 * CONFIG_SYS_HZ, false);
|
||||
|
||||
/* clear any existing interrupt event */
|
||||
writel(0xffffffff, &ectl_p->irq.clr);
|
||||
}
|
||||
|
||||
static int pic32_eth_send(struct udevice *dev, void *packet, int length)
|
||||
{
|
||||
struct pic32eth_dev *priv = dev_get_priv(dev);
|
||||
struct pic32_ectl_regs *ectl_p = priv->ectl_regs;
|
||||
struct eth_dma_desc *txd;
|
||||
u64 deadline;
|
||||
|
||||
txd = &priv->txd_ring[0];
|
||||
|
||||
/* set proper flags & length in descriptor header */
|
||||
txd->hdr = EDH_SOP | EDH_EOP | EDH_EOWN | EDH_BCOUNT(length);
|
||||
|
||||
/* pass buffer address to hardware */
|
||||
txd->data_buff = virt_to_phys(packet);
|
||||
|
||||
debug("%s: %d / .hdr %x, .data_buff %x, .stat %x, .nexted %x\n",
|
||||
__func__, __LINE__, txd->hdr, txd->data_buff, txd->stat2,
|
||||
txd->next_ed);
|
||||
|
||||
/* cache flush (packet) */
|
||||
flush_dcache_range((ulong)packet, (ulong)packet + length);
|
||||
|
||||
/* cache flush (txd) */
|
||||
flush_dcache_range((ulong)txd, (ulong)txd + sizeof(*txd));
|
||||
|
||||
/* pass descriptor table base to h/w */
|
||||
writel(virt_to_phys(txd), &ectl_p->txst.raw);
|
||||
|
||||
/* ready to send enabled, hardware can now send the packet(s) */
|
||||
writel(ETHCON_TXRTS | ETHCON_ON, &ectl_p->con1.set);
|
||||
|
||||
/* wait until tx has completed and h/w has released ownership
|
||||
* of the tx descriptor or timeout elapsed.
|
||||
*/
|
||||
deadline = get_ticks() + get_tbclk();
|
||||
for (;;) {
|
||||
/* check timeout */
|
||||
if (get_ticks() > deadline)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
if (ctrlc())
|
||||
return -EINTR;
|
||||
|
||||
/* tx completed ? */
|
||||
if (readl(&ectl_p->con1.raw) & ETHCON_TXRTS) {
|
||||
udelay(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* h/w not released ownership yet? */
|
||||
invalidate_dcache_range((ulong)txd, (ulong)txd + sizeof(*txd));
|
||||
if (!(txd->hdr & EDH_EOWN))
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pic32_eth_recv(struct udevice *dev, int flags, uchar **packetp)
|
||||
{
|
||||
struct pic32eth_dev *priv = dev_get_priv(dev);
|
||||
struct eth_dma_desc *rxd;
|
||||
u32 idx = priv->rxd_idx;
|
||||
u32 rx_count;
|
||||
|
||||
/* find the next ready to receive */
|
||||
rxd = &priv->rxd_ring[idx];
|
||||
|
||||
invalidate_dcache_range((ulong)rxd, (ulong)rxd + sizeof(*rxd));
|
||||
/* check if owned by MAC */
|
||||
if (rxd->hdr & EDH_EOWN)
|
||||
return -EAGAIN;
|
||||
|
||||
/* Sanity check on header: SOP and EOP */
|
||||
if ((rxd->hdr & (EDH_SOP | EDH_EOP)) != (EDH_SOP | EDH_EOP)) {
|
||||
printf("%s: %s, rx pkt across multiple descr\n",
|
||||
__FILE__, __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug("%s: %d /idx %i, hdr=%x, data_buff %x, stat %x, nexted %x\n",
|
||||
__func__, __LINE__, idx, rxd->hdr,
|
||||
rxd->data_buff, rxd->stat2, rxd->next_ed);
|
||||
|
||||
/* Sanity check on rx_stat: OK, CRC */
|
||||
if (!RSV_RX_OK(rxd->stat2) || RSV_CRC_ERR(rxd->stat2)) {
|
||||
debug("%s: %s: Error, rx problem detected\n",
|
||||
__FILE__, __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* invalidate dcache */
|
||||
rx_count = RSV_RX_COUNT(rxd->stat2);
|
||||
invalidate_dcache_range((ulong)net_rx_packets[idx],
|
||||
(ulong)net_rx_packets[idx] + rx_count);
|
||||
|
||||
/* Pass the packet to protocol layer */
|
||||
*packetp = net_rx_packets[idx];
|
||||
|
||||
/* increment number of bytes rcvd (ignore CRC) */
|
||||
return rx_count - 4;
|
||||
}
|
||||
|
||||
static int pic32_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
|
||||
{
|
||||
struct pic32eth_dev *priv = dev_get_priv(dev);
|
||||
struct pic32_ectl_regs *ectl_p = priv->ectl_regs;
|
||||
struct eth_dma_desc *rxd;
|
||||
int idx = priv->rxd_idx;
|
||||
|
||||
/* sanity check */
|
||||
if (packet != net_rx_packets[idx]) {
|
||||
printf("rxd_id %d: packet is not matched,\n", idx);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/* prepare for receive */
|
||||
rxd = &priv->rxd_ring[idx];
|
||||
rxd->hdr = EDH_STICKY | EDH_NPV | EDH_EOWN;
|
||||
|
||||
flush_dcache_range((ulong)rxd, (ulong)rxd + sizeof(*rxd));
|
||||
|
||||
/* decrement rx pkt count */
|
||||
writel(ETHCON_BUFCDEC, &ectl_p->con1.set);
|
||||
|
||||
debug("%s: %d / idx %i, hdr %x, data_buff %x, stat %x, nexted %x\n",
|
||||
__func__, __LINE__, idx, rxd->hdr, rxd->data_buff,
|
||||
rxd->stat2, rxd->next_ed);
|
||||
|
||||
priv->rxd_idx = (priv->rxd_idx + 1) % MAX_RX_DESCR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct eth_ops pic32_eth_ops = {
|
||||
.start = pic32_eth_start,
|
||||
.send = pic32_eth_send,
|
||||
.recv = pic32_eth_recv,
|
||||
.free_pkt = pic32_eth_free_pkt,
|
||||
.stop = pic32_eth_stop,
|
||||
};
|
||||
|
||||
static int pic32_eth_probe(struct udevice *dev)
|
||||
{
|
||||
struct eth_pdata *pdata = dev_get_platdata(dev);
|
||||
struct pic32eth_dev *priv = dev_get_priv(dev);
|
||||
const char *phy_mode;
|
||||
void __iomem *iobase;
|
||||
fdt_addr_t addr;
|
||||
fdt_size_t size;
|
||||
int offset = 0;
|
||||
int phy_addr = -1;
|
||||
|
||||
addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg", &size);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
iobase = ioremap(addr, size);
|
||||
pdata->iobase = (phys_addr_t)addr;
|
||||
|
||||
/* get phy mode */
|
||||
pdata->phy_interface = -1;
|
||||
phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset, "phy-mode", NULL);
|
||||
if (phy_mode)
|
||||
pdata->phy_interface = phy_get_interface_by_name(phy_mode);
|
||||
if (pdata->phy_interface == -1) {
|
||||
debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* get phy addr */
|
||||
offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
|
||||
"phy-handle");
|
||||
if (offset > 0)
|
||||
phy_addr = fdtdec_get_int(gd->fdt_blob, offset, "reg", -1);
|
||||
|
||||
/* phy reset gpio */
|
||||
gpio_request_by_name_nodev(gd->fdt_blob, dev->of_offset,
|
||||
"reset-gpios", 0,
|
||||
&priv->rst_gpio, GPIOD_IS_OUT);
|
||||
|
||||
priv->phyif = pdata->phy_interface;
|
||||
priv->phy_addr = phy_addr;
|
||||
priv->ectl_regs = iobase;
|
||||
priv->emac_regs = iobase + PIC32_EMAC1CFG1;
|
||||
|
||||
pic32_mii_init(priv);
|
||||
|
||||
return pic32_phy_init(priv, dev);
|
||||
}
|
||||
|
||||
static int pic32_eth_remove(struct udevice *dev)
|
||||
{
|
||||
struct pic32eth_dev *priv = dev_get_priv(dev);
|
||||
struct mii_dev *bus;
|
||||
|
||||
dm_gpio_free(dev, &priv->rst_gpio);
|
||||
phy_shutdown(priv->phydev);
|
||||
free(priv->phydev);
|
||||
bus = miiphy_get_dev_by_name(PIC32_MDIO_NAME);
|
||||
mdio_unregister(bus);
|
||||
mdio_free(bus);
|
||||
iounmap(priv->ectl_regs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id pic32_eth_ids[] = {
|
||||
{ .compatible = "microchip,pic32mzda-eth" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(pic32_ethernet) = {
|
||||
.name = "pic32_ethernet",
|
||||
.id = UCLASS_ETH,
|
||||
.of_match = pic32_eth_ids,
|
||||
.probe = pic32_eth_probe,
|
||||
.remove = pic32_eth_remove,
|
||||
.ops = &pic32_eth_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct pic32eth_dev),
|
||||
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
|
||||
};
|
164
drivers/net/pic32_eth.h
Normal file
164
drivers/net/pic32_eth.h
Normal file
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* (c) 2015 Purna Chandra Mandal <purna.mandal@microchip.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MICROCHIP_PIC32_ETH_H_
|
||||
#define __MICROCHIP_PIC32_ETH_H_
|
||||
|
||||
#include <mach/pic32.h>
|
||||
|
||||
/* Ethernet */
|
||||
struct pic32_ectl_regs {
|
||||
struct pic32_reg_atomic con1; /* 0x00 */
|
||||
struct pic32_reg_atomic con2; /* 0x10 */
|
||||
struct pic32_reg_atomic txst; /* 0x20 */
|
||||
struct pic32_reg_atomic rxst; /* 0x30 */
|
||||
struct pic32_reg_atomic ht0; /* 0x40 */
|
||||
struct pic32_reg_atomic ht1; /* 0x50 */
|
||||
struct pic32_reg_atomic pmm0; /* 0x60 */
|
||||
struct pic32_reg_atomic pmm1; /* 0x70 */
|
||||
struct pic32_reg_atomic pmcs; /* 0x80 */
|
||||
struct pic32_reg_atomic pmo; /* 0x90 */
|
||||
struct pic32_reg_atomic rxfc; /* 0xa0 */
|
||||
struct pic32_reg_atomic rxwm; /* 0xb0 */
|
||||
struct pic32_reg_atomic ien; /* 0xc0 */
|
||||
struct pic32_reg_atomic irq; /* 0xd0 */
|
||||
struct pic32_reg_atomic stat; /* 0xe0 */
|
||||
};
|
||||
|
||||
struct pic32_mii_regs {
|
||||
struct pic32_reg_atomic mcfg; /* 0x280 */
|
||||
struct pic32_reg_atomic mcmd; /* 0x290 */
|
||||
struct pic32_reg_atomic madr; /* 0x2a0 */
|
||||
struct pic32_reg_atomic mwtd; /* 0x2b0 */
|
||||
struct pic32_reg_atomic mrdd; /* 0x2c0 */
|
||||
struct pic32_reg_atomic mind; /* 0x2d0 */
|
||||
};
|
||||
|
||||
struct pic32_emac_regs {
|
||||
struct pic32_reg_atomic cfg1; /* 0x200*/
|
||||
struct pic32_reg_atomic cfg2; /* 0x210*/
|
||||
struct pic32_reg_atomic ipgt; /* 0x220*/
|
||||
struct pic32_reg_atomic ipgr; /* 0x230*/
|
||||
struct pic32_reg_atomic clrt; /* 0x240*/
|
||||
struct pic32_reg_atomic maxf; /* 0x250*/
|
||||
struct pic32_reg_atomic supp; /* 0x260*/
|
||||
struct pic32_reg_atomic test; /* 0x270*/
|
||||
struct pic32_mii_regs mii; /* 0x280 - 0x2d0 */
|
||||
struct pic32_reg_atomic res1; /* 0x2e0 */
|
||||
struct pic32_reg_atomic res2; /* 0x2f0 */
|
||||
struct pic32_reg_atomic sa0; /* 0x300 */
|
||||
struct pic32_reg_atomic sa1; /* 0x310 */
|
||||
struct pic32_reg_atomic sa2; /* 0x320 */
|
||||
};
|
||||
|
||||
/* ETHCON1 Reg field */
|
||||
#define ETHCON_BUFCDEC BIT(0)
|
||||
#define ETHCON_RXEN BIT(8)
|
||||
#define ETHCON_TXRTS BIT(9)
|
||||
#define ETHCON_ON BIT(15)
|
||||
|
||||
/* ETHCON2 Reg field */
|
||||
#define ETHCON_RXBUFSZ 0x7f
|
||||
#define ETHCON_RXBUFSZ_SHFT 0x4
|
||||
|
||||
/* ETHSTAT Reg field */
|
||||
#define ETHSTAT_BUSY BIT(7)
|
||||
#define ETHSTAT_BUFCNT 0x00ff0000
|
||||
|
||||
/* ETHRXFC Register fields */
|
||||
#define ETHRXFC_BCEN BIT(0)
|
||||
#define ETHRXFC_MCEN BIT(1)
|
||||
#define ETHRXFC_UCEN BIT(3)
|
||||
#define ETHRXFC_RUNTEN BIT(4)
|
||||
#define ETHRXFC_CRCOKEN BIT(5)
|
||||
|
||||
/* EMAC1CFG1 register offset */
|
||||
#define PIC32_EMAC1CFG1 0x0200
|
||||
|
||||
/* EMAC1CFG1 register fields */
|
||||
#define EMAC_RXENABLE BIT(0)
|
||||
#define EMAC_RXPAUSE BIT(2)
|
||||
#define EMAC_TXPAUSE BIT(3)
|
||||
#define EMAC_SOFTRESET BIT(15)
|
||||
|
||||
/* EMAC1CFG2 register fields */
|
||||
#define EMAC_FULLDUP BIT(0)
|
||||
#define EMAC_LENGTHCK BIT(1)
|
||||
#define EMAC_CRCENABLE BIT(4)
|
||||
#define EMAC_PADENABLE BIT(5)
|
||||
#define EMAC_AUTOPAD BIT(7)
|
||||
#define EMAC_EXCESS BIT(14)
|
||||
|
||||
/* EMAC1IPGT register magic */
|
||||
#define FULLDUP_GAP_TIME 0x15
|
||||
#define HALFDUP_GAP_TIME 0x12
|
||||
|
||||
/* EMAC1SUPP register fields */
|
||||
#define EMAC_RMII_SPD100 BIT(8)
|
||||
#define EMAC_RMII_RESET BIT(11)
|
||||
|
||||
/* MII Management Configuration Register */
|
||||
#define MIIMCFG_RSTMGMT BIT(15)
|
||||
#define MIIMCFG_CLKSEL_DIV40 0x0020 /* 100Mhz / 40 */
|
||||
|
||||
/* MII Management Command Register */
|
||||
#define MIIMCMD_READ BIT(0)
|
||||
#define MIIMCMD_SCAN BIT(1)
|
||||
|
||||
/* MII Management Address Register */
|
||||
#define MIIMADD_REGADDR 0x1f
|
||||
#define MIIMADD_REGADDR_SHIFT 0
|
||||
#define MIIMADD_PHYADDR_SHIFT 8
|
||||
|
||||
/* MII Management Indicator Register */
|
||||
#define MIIMIND_BUSY BIT(0)
|
||||
#define MIIMIND_NOTVALID BIT(2)
|
||||
#define MIIMIND_LINKFAIL BIT(3)
|
||||
|
||||
/* Packet Descriptor */
|
||||
/* Received Packet Status */
|
||||
#define _RSV1_PKT_CSUM 0xffff
|
||||
#define _RSV2_CRC_ERR BIT(20)
|
||||
#define _RSV2_LEN_ERR BIT(21)
|
||||
#define _RSV2_RX_OK BIT(23)
|
||||
#define _RSV2_RX_COUNT 0xffff
|
||||
|
||||
#define RSV_RX_CSUM(__rsv1) ((__rsv1) & _RSV1_PKT_CSUM)
|
||||
#define RSV_RX_COUNT(__rsv2) ((__rsv2) & _RSV2_RX_COUNT)
|
||||
#define RSV_RX_OK(__rsv2) ((__rsv2) & _RSV2_RX_OK)
|
||||
#define RSV_CRC_ERR(__rsv2) ((__rsv2) & _RSV2_CRC_ERR)
|
||||
|
||||
/* Ethernet Hardware Descriptor Header bits */
|
||||
#define EDH_EOWN BIT(7)
|
||||
#define EDH_NPV BIT(8)
|
||||
#define EDH_STICKY BIT(9)
|
||||
#define _EDH_BCOUNT 0x07ff0000
|
||||
#define EDH_EOP BIT(30)
|
||||
#define EDH_SOP BIT(31)
|
||||
#define EDH_BCOUNT_SHIFT 16
|
||||
#define EDH_BCOUNT(len) ((len) << EDH_BCOUNT_SHIFT)
|
||||
|
||||
/* Ethernet Hardware Descriptors
|
||||
* ref: PIC32 Family Reference Manual Table 35-7
|
||||
* This structure represents the layout of the DMA
|
||||
* memory shared between the CPU and the Ethernet
|
||||
* controller.
|
||||
*/
|
||||
/* TX/RX DMA descriptor */
|
||||
struct eth_dma_desc {
|
||||
u32 hdr; /* header */
|
||||
u32 data_buff; /* data buffer address */
|
||||
u32 stat1; /* transmit/receive packet status */
|
||||
u32 stat2; /* transmit/receive packet status */
|
||||
u32 next_ed; /* next descriptor */
|
||||
};
|
||||
|
||||
#define PIC32_MDIO_NAME "PIC32_EMAC"
|
||||
|
||||
int pic32_mdio_init(const char *name, ulong ioaddr);
|
||||
|
||||
#endif /* __MICROCHIP_PIC32_ETH_H_*/
|
121
drivers/net/pic32_mdio.c
Normal file
121
drivers/net/pic32_mdio.c
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* pic32_mdio.c: PIC32 MDIO/MII driver, part of pic32_eth.c.
|
||||
*
|
||||
* Copyright 2015 Microchip Inc.
|
||||
* Purna Chandra Mandal <purna.mandal@microchip.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <phy.h>
|
||||
#include <miiphy.h>
|
||||
#include <errno.h>
|
||||
#include <wait_bit.h>
|
||||
#include <asm/io.h>
|
||||
#include "pic32_eth.h"
|
||||
|
||||
static int pic32_mdio_write(struct mii_dev *bus,
|
||||
int addr, int dev_addr,
|
||||
int reg, u16 value)
|
||||
{
|
||||
u32 v;
|
||||
struct pic32_mii_regs *mii_regs = bus->priv;
|
||||
|
||||
/* Wait for the previous operation to finish */
|
||||
wait_for_bit(__func__, &mii_regs->mind.raw, MIIMIND_BUSY,
|
||||
false, CONFIG_SYS_HZ, true);
|
||||
|
||||
/* Put phyaddr and regaddr into MIIMADD */
|
||||
v = (addr << MIIMADD_PHYADDR_SHIFT) | (reg & MIIMADD_REGADDR);
|
||||
writel(v, &mii_regs->madr.raw);
|
||||
|
||||
/* Initiate a write command */
|
||||
writel(value, &mii_regs->mwtd.raw);
|
||||
|
||||
/* Wait 30 clock cycles for busy flag to be set */
|
||||
udelay(12);
|
||||
|
||||
/* Wait for write to complete */
|
||||
wait_for_bit(__func__, &mii_regs->mind.raw, MIIMIND_BUSY,
|
||||
false, CONFIG_SYS_HZ, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pic32_mdio_read(struct mii_dev *bus, int addr, int devaddr, int reg)
|
||||
{
|
||||
u32 v;
|
||||
struct pic32_mii_regs *mii_regs = bus->priv;
|
||||
|
||||
/* Wait for the previous operation to finish */
|
||||
wait_for_bit(__func__, &mii_regs->mind.raw, MIIMIND_BUSY,
|
||||
false, CONFIG_SYS_HZ, true);
|
||||
|
||||
/* Put phyaddr and regaddr into MIIMADD */
|
||||
v = (addr << MIIMADD_PHYADDR_SHIFT) | (reg & MIIMADD_REGADDR);
|
||||
writel(v, &mii_regs->madr.raw);
|
||||
|
||||
/* Initiate a read command */
|
||||
writel(MIIMCMD_READ, &mii_regs->mcmd.raw);
|
||||
|
||||
/* Wait 30 clock cycles for busy flag to be set */
|
||||
udelay(12);
|
||||
|
||||
/* Wait for read to complete */
|
||||
wait_for_bit(__func__, &mii_regs->mind.raw,
|
||||
MIIMIND_NOTVALID | MIIMIND_BUSY,
|
||||
false, CONFIG_SYS_HZ, false);
|
||||
|
||||
/* Clear the command register */
|
||||
writel(0, &mii_regs->mcmd.raw);
|
||||
|
||||
/* Grab the value read from the PHY */
|
||||
v = readl(&mii_regs->mrdd.raw);
|
||||
return v;
|
||||
}
|
||||
|
||||
static int pic32_mdio_reset(struct mii_dev *bus)
|
||||
{
|
||||
struct pic32_mii_regs *mii_regs = bus->priv;
|
||||
|
||||
/* Reset MII (due to new addresses) */
|
||||
writel(MIIMCFG_RSTMGMT, &mii_regs->mcfg.raw);
|
||||
|
||||
/* Wait for the operation to finish */
|
||||
wait_for_bit(__func__, &mii_regs->mind.raw, MIIMIND_BUSY,
|
||||
false, CONFIG_SYS_HZ, true);
|
||||
|
||||
/* Clear reset bit */
|
||||
writel(0, &mii_regs->mcfg);
|
||||
|
||||
/* Wait for the operation to finish */
|
||||
wait_for_bit(__func__, &mii_regs->mind.raw, MIIMIND_BUSY,
|
||||
false, CONFIG_SYS_HZ, true);
|
||||
|
||||
/* Set the MII Management Clock (MDC) - no faster than 2.5 MHz */
|
||||
writel(MIIMCFG_CLKSEL_DIV40, &mii_regs->mcfg.raw);
|
||||
|
||||
/* Wait for the operation to finish */
|
||||
wait_for_bit(__func__, &mii_regs->mind.raw, MIIMIND_BUSY,
|
||||
false, CONFIG_SYS_HZ, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pic32_mdio_init(const char *name, ulong ioaddr)
|
||||
{
|
||||
struct mii_dev *bus;
|
||||
|
||||
bus = mdio_alloc();
|
||||
if (!bus) {
|
||||
printf("Failed to allocate PIC32-MDIO bus\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
bus->read = pic32_mdio_read;
|
||||
bus->write = pic32_mdio_write;
|
||||
bus->reset = pic32_mdio_reset;
|
||||
strncpy(bus->name, name, sizeof(bus->name));
|
||||
bus->priv = (void *)ioaddr;
|
||||
|
||||
return mdio_register(bus);
|
||||
}
|
|
@ -131,6 +131,16 @@ config PINCTRL_SANDBOX
|
|||
actually does nothing but print debug messages when pinctrl
|
||||
operations are invoked.
|
||||
|
||||
config PIC32_PINCTRL
|
||||
bool "Microchip PIC32 pin-control and pin-mux driver"
|
||||
depends on DM && MACH_PIC32
|
||||
default y
|
||||
help
|
||||
Supports individual pin selection and configuration for each remappable
|
||||
peripheral available on Microchip PIC32 SoCs. This driver is controlled
|
||||
by a device tree node which contains both GPIO defintion and pin control
|
||||
functions.
|
||||
|
||||
endif
|
||||
|
||||
source "drivers/pinctrl/uniphier/Kconfig"
|
||||
|
|
|
@ -9,3 +9,4 @@ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
|
|||
obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o
|
||||
|
||||
obj-$(CONFIG_ARCH_UNIPHIER) += uniphier/
|
||||
obj-$(CONFIG_PIC32_PINCTRL) += pinctrl_pic32.o
|
||||
|
|
363
drivers/pinctrl/pinctrl_pic32.c
Normal file
363
drivers/pinctrl/pinctrl_pic32.c
Normal file
|
@ -0,0 +1,363 @@
|
|||
/*
|
||||
* Pinctrl driver for Microchip PIC32 SoCs
|
||||
* Copyright (c) 2015 Microchip Technology Inc.
|
||||
* Written by Purna Chandra Mandal <purna.mandal@microchip.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <asm/io.h>
|
||||
#include <dm/pinctrl.h>
|
||||
#include <dm/root.h>
|
||||
#include <mach/pic32.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/* PIC32 has 10 peripheral ports with 16 pins each.
|
||||
* Ports are marked PORTA-PORTK or PORT0-PORT9.
|
||||
*/
|
||||
enum {
|
||||
PIC32_PORT_A = 0,
|
||||
PIC32_PORT_B = 1,
|
||||
PIC32_PORT_C = 2,
|
||||
PIC32_PORT_D = 3,
|
||||
PIC32_PORT_E = 4,
|
||||
PIC32_PORT_F = 5,
|
||||
PIC32_PORT_G = 6,
|
||||
PIC32_PORT_H = 7,
|
||||
PIC32_PORT_J = 8, /* no PORT_I */
|
||||
PIC32_PORT_K = 9,
|
||||
PIC32_PINS_PER_PORT = 16,
|
||||
};
|
||||
|
||||
#define PIN_CONFIG_PIC32_DIGITAL (PIN_CONFIG_END + 1)
|
||||
#define PIN_CONFIG_PIC32_ANALOG (PIN_CONFIG_END + 2)
|
||||
|
||||
/* pin configuration descriptor */
|
||||
struct pic32_pin_config {
|
||||
u16 port; /* port number */
|
||||
u16 pin; /* pin number in the port */
|
||||
u32 config; /* one of PIN_CONFIG_* */
|
||||
};
|
||||
#define PIN_CONFIG(_prt, _pin, _cfg) \
|
||||
{.port = (_prt), .pin = (_pin), .config = (_cfg), }
|
||||
|
||||
/* In PIC32 muxing is performed at pin-level through two
|
||||
* different set of registers - one set for input functions,
|
||||
* and other for output functions.
|
||||
* Pin configuration is handled through port register.
|
||||
*/
|
||||
/* Port control registers */
|
||||
struct pic32_reg_port {
|
||||
struct pic32_reg_atomic ansel;
|
||||
struct pic32_reg_atomic tris;
|
||||
struct pic32_reg_atomic port;
|
||||
struct pic32_reg_atomic lat;
|
||||
struct pic32_reg_atomic odc;
|
||||
struct pic32_reg_atomic cnpu;
|
||||
struct pic32_reg_atomic cnpd;
|
||||
struct pic32_reg_atomic cncon;
|
||||
struct pic32_reg_atomic unused[8];
|
||||
};
|
||||
|
||||
/* Input function mux registers */
|
||||
struct pic32_reg_in_mux {
|
||||
u32 unused0;
|
||||
u32 int1[4];
|
||||
u32 unused1;
|
||||
u32 t2ck[8];
|
||||
u32 ic1[9];
|
||||
u32 unused2;
|
||||
u32 ocfar;
|
||||
u32 unused3;
|
||||
u32 u1rx;
|
||||
u32 u1cts;
|
||||
u32 u2rx;
|
||||
u32 u2cts;
|
||||
u32 u3rx;
|
||||
u32 u3cts;
|
||||
u32 u4rx;
|
||||
u32 u4cts;
|
||||
u32 u5rx;
|
||||
u32 u5cts;
|
||||
u32 u6rx;
|
||||
u32 u6cts;
|
||||
u32 unused4;
|
||||
u32 sdi1;
|
||||
u32 ss1;
|
||||
u32 unused5;
|
||||
u32 sdi2;
|
||||
u32 ss2;
|
||||
u32 unused6;
|
||||
u32 sdi3;
|
||||
u32 ss3;
|
||||
u32 unused7;
|
||||
u32 sdi4;
|
||||
u32 ss4;
|
||||
u32 unused8;
|
||||
u32 sdi5;
|
||||
u32 ss5;
|
||||
u32 unused9;
|
||||
u32 sdi6;
|
||||
u32 ss6;
|
||||
u32 c1rx;
|
||||
u32 c2rx;
|
||||
u32 refclki1;
|
||||
u32 refclki2;
|
||||
u32 refclki3;
|
||||
u32 refclki4;
|
||||
};
|
||||
|
||||
/* output mux register offset */
|
||||
#define PPS_OUT(__port, __pin) \
|
||||
(((__port) * PIC32_PINS_PER_PORT + (__pin)) << 2)
|
||||
|
||||
|
||||
struct pic32_pinctrl_priv {
|
||||
struct pic32_reg_in_mux *mux_in; /* mux input function */
|
||||
struct pic32_reg_port *pinconf; /* pin configuration*/
|
||||
void __iomem *mux_out; /* mux output function */
|
||||
};
|
||||
|
||||
enum {
|
||||
PERIPH_ID_UART1,
|
||||
PERIPH_ID_UART2,
|
||||
PERIPH_ID_ETH,
|
||||
PERIPH_ID_USB,
|
||||
PERIPH_ID_SDHCI,
|
||||
PERIPH_ID_I2C1,
|
||||
PERIPH_ID_I2C2,
|
||||
PERIPH_ID_SPI1,
|
||||
PERIPH_ID_SPI2,
|
||||
PERIPH_ID_SQI,
|
||||
};
|
||||
|
||||
static int pic32_pinconfig_one(struct pic32_pinctrl_priv *priv,
|
||||
u32 port_nr, u32 pin, u32 param)
|
||||
{
|
||||
struct pic32_reg_port *port;
|
||||
|
||||
port = &priv->pinconf[port_nr];
|
||||
switch (param) {
|
||||
case PIN_CONFIG_PIC32_DIGITAL:
|
||||
writel(BIT(pin), &port->ansel.clr);
|
||||
break;
|
||||
case PIN_CONFIG_PIC32_ANALOG:
|
||||
writel(BIT(pin), &port->ansel.set);
|
||||
break;
|
||||
case PIN_CONFIG_INPUT_ENABLE:
|
||||
writel(BIT(pin), &port->tris.set);
|
||||
break;
|
||||
case PIN_CONFIG_OUTPUT:
|
||||
writel(BIT(pin), &port->tris.clr);
|
||||
break;
|
||||
case PIN_CONFIG_BIAS_PULL_UP:
|
||||
writel(BIT(pin), &port->cnpu.set);
|
||||
break;
|
||||
case PIN_CONFIG_BIAS_PULL_DOWN:
|
||||
writel(BIT(pin), &port->cnpd.set);
|
||||
break;
|
||||
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
|
||||
writel(BIT(pin), &port->odc.set);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pic32_pinconfig_set(struct pic32_pinctrl_priv *priv,
|
||||
const struct pic32_pin_config *list, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0 ; i < count; i++)
|
||||
pic32_pinconfig_one(priv, list[i].port,
|
||||
list[i].pin, list[i].config);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pic32_eth_pin_config(struct udevice *dev)
|
||||
{
|
||||
struct pic32_pinctrl_priv *priv = dev_get_priv(dev);
|
||||
const struct pic32_pin_config configs[] = {
|
||||
/* EMDC - D11 */
|
||||
PIN_CONFIG(PIC32_PORT_D, 11, PIN_CONFIG_PIC32_DIGITAL),
|
||||
PIN_CONFIG(PIC32_PORT_D, 11, PIN_CONFIG_OUTPUT),
|
||||
/* ETXEN */
|
||||
PIN_CONFIG(PIC32_PORT_D, 6, PIN_CONFIG_PIC32_DIGITAL),
|
||||
PIN_CONFIG(PIC32_PORT_D, 6, PIN_CONFIG_OUTPUT),
|
||||
/* ECRSDV */
|
||||
PIN_CONFIG(PIC32_PORT_H, 13, PIN_CONFIG_PIC32_DIGITAL),
|
||||
PIN_CONFIG(PIC32_PORT_H, 13, PIN_CONFIG_INPUT_ENABLE),
|
||||
/* ERXD0 */
|
||||
PIN_CONFIG(PIC32_PORT_H, 8, PIN_CONFIG_PIC32_DIGITAL),
|
||||
PIN_CONFIG(PIC32_PORT_H, 8, PIN_CONFIG_INPUT_ENABLE),
|
||||
PIN_CONFIG(PIC32_PORT_H, 8, PIN_CONFIG_BIAS_PULL_DOWN),
|
||||
/* ERXD1 */
|
||||
PIN_CONFIG(PIC32_PORT_H, 5, PIN_CONFIG_PIC32_DIGITAL),
|
||||
PIN_CONFIG(PIC32_PORT_H, 5, PIN_CONFIG_INPUT_ENABLE),
|
||||
PIN_CONFIG(PIC32_PORT_H, 5, PIN_CONFIG_BIAS_PULL_DOWN),
|
||||
/* EREFCLK */
|
||||
PIN_CONFIG(PIC32_PORT_J, 11, PIN_CONFIG_PIC32_DIGITAL),
|
||||
PIN_CONFIG(PIC32_PORT_J, 11, PIN_CONFIG_INPUT_ENABLE),
|
||||
/* ETXD1 */
|
||||
PIN_CONFIG(PIC32_PORT_J, 9, PIN_CONFIG_PIC32_DIGITAL),
|
||||
PIN_CONFIG(PIC32_PORT_J, 9, PIN_CONFIG_OUTPUT),
|
||||
/* ETXD0 */
|
||||
PIN_CONFIG(PIC32_PORT_J, 8, PIN_CONFIG_PIC32_DIGITAL),
|
||||
PIN_CONFIG(PIC32_PORT_J, 8, PIN_CONFIG_OUTPUT),
|
||||
/* EMDIO */
|
||||
PIN_CONFIG(PIC32_PORT_J, 1, PIN_CONFIG_PIC32_DIGITAL),
|
||||
PIN_CONFIG(PIC32_PORT_J, 1, PIN_CONFIG_INPUT_ENABLE),
|
||||
/* ERXERR */
|
||||
PIN_CONFIG(PIC32_PORT_F, 3, PIN_CONFIG_PIC32_DIGITAL),
|
||||
PIN_CONFIG(PIC32_PORT_F, 3, PIN_CONFIG_INPUT_ENABLE),
|
||||
};
|
||||
|
||||
pic32_pinconfig_set(priv, configs, ARRAY_SIZE(configs));
|
||||
}
|
||||
|
||||
static int pic32_pinctrl_request(struct udevice *dev, int func, int flags)
|
||||
{
|
||||
struct pic32_pinctrl_priv *priv = dev_get_priv(dev);
|
||||
|
||||
switch (func) {
|
||||
case PERIPH_ID_UART2:
|
||||
/* PPS for U2 RX/TX */
|
||||
writel(0x02, priv->mux_out + PPS_OUT(PIC32_PORT_G, 9));
|
||||
writel(0x05, &priv->mux_in->u2rx); /* B0 */
|
||||
/* set digital mode */
|
||||
pic32_pinconfig_one(priv, PIC32_PORT_G, 9,
|
||||
PIN_CONFIG_PIC32_DIGITAL);
|
||||
pic32_pinconfig_one(priv, PIC32_PORT_B, 0,
|
||||
PIN_CONFIG_PIC32_DIGITAL);
|
||||
break;
|
||||
case PERIPH_ID_ETH:
|
||||
pic32_eth_pin_config(dev);
|
||||
break;
|
||||
default:
|
||||
debug("%s: unknown-unhandled case\n", __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pic32_pinctrl_get_periph_id(struct udevice *dev,
|
||||
struct udevice *periph)
|
||||
{
|
||||
int ret;
|
||||
u32 cell[2];
|
||||
|
||||
ret = fdtdec_get_int_array(gd->fdt_blob, periph->of_offset,
|
||||
"interrupts", cell, ARRAY_SIZE(cell));
|
||||
if (ret < 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* interrupt number */
|
||||
switch (cell[0]) {
|
||||
case 112 ... 114:
|
||||
return PERIPH_ID_UART1;
|
||||
case 145 ... 147:
|
||||
return PERIPH_ID_UART2;
|
||||
case 109 ... 111:
|
||||
return PERIPH_ID_SPI1;
|
||||
case 142 ... 144:
|
||||
return PERIPH_ID_SPI2;
|
||||
case 115 ... 117:
|
||||
return PERIPH_ID_I2C1;
|
||||
case 148 ... 150:
|
||||
return PERIPH_ID_I2C2;
|
||||
case 132 ... 133:
|
||||
return PERIPH_ID_USB;
|
||||
case 169:
|
||||
return PERIPH_ID_SQI;
|
||||
case 191:
|
||||
return PERIPH_ID_SDHCI;
|
||||
case 153:
|
||||
return PERIPH_ID_ETH;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int pic32_pinctrl_set_state_simple(struct udevice *dev,
|
||||
struct udevice *periph)
|
||||
{
|
||||
int func;
|
||||
|
||||
debug("%s: periph %s\n", __func__, periph->name);
|
||||
func = pic32_pinctrl_get_periph_id(dev, periph);
|
||||
if (func < 0)
|
||||
return func;
|
||||
return pic32_pinctrl_request(dev, func, 0);
|
||||
}
|
||||
|
||||
static struct pinctrl_ops pic32_pinctrl_ops = {
|
||||
.set_state_simple = pic32_pinctrl_set_state_simple,
|
||||
.request = pic32_pinctrl_request,
|
||||
.get_periph_id = pic32_pinctrl_get_periph_id,
|
||||
};
|
||||
|
||||
static int pic32_pinctrl_probe(struct udevice *dev)
|
||||
{
|
||||
struct pic32_pinctrl_priv *priv = dev_get_priv(dev);
|
||||
struct fdt_resource res;
|
||||
void *fdt = (void *)gd->fdt_blob;
|
||||
int node = dev->of_offset;
|
||||
int ret;
|
||||
|
||||
ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
|
||||
"ppsin", &res);
|
||||
if (ret < 0) {
|
||||
printf("pinctrl: resource \"ppsin\" not found\n");
|
||||
return ret;
|
||||
}
|
||||
priv->mux_in = ioremap(res.start, fdt_resource_size(&res));
|
||||
|
||||
ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
|
||||
"ppsout", &res);
|
||||
if (ret < 0) {
|
||||
printf("pinctrl: resource \"ppsout\" not found\n");
|
||||
return ret;
|
||||
}
|
||||
priv->mux_out = ioremap(res.start, fdt_resource_size(&res));
|
||||
|
||||
ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
|
||||
"port", &res);
|
||||
if (ret < 0) {
|
||||
printf("pinctrl: resource \"port\" not found\n");
|
||||
return ret;
|
||||
}
|
||||
priv->pinconf = ioremap(res.start, fdt_resource_size(&res));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pic32_pinctrl_bind(struct udevice *dev)
|
||||
{
|
||||
/* scan child GPIO banks */
|
||||
return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
|
||||
}
|
||||
|
||||
static const struct udevice_id pic32_pinctrl_ids[] = {
|
||||
{ .compatible = "microchip,pic32mzda-pinctrl" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(pinctrl_pic32) = {
|
||||
.name = "pinctrl_pic32",
|
||||
.id = UCLASS_PINCTRL,
|
||||
.of_match = pic32_pinctrl_ids,
|
||||
.ops = &pic32_pinctrl_ops,
|
||||
.probe = pic32_pinctrl_probe,
|
||||
.bind = pic32_pinctrl_bind,
|
||||
.priv_auto_alloc_size = sizeof(struct pic32_pinctrl_priv),
|
||||
};
|
|
@ -150,6 +150,14 @@ config DEBUG_UART_PL011
|
|||
work. The driver will be available until the real driver model
|
||||
serial is running.
|
||||
|
||||
config DEBUG_UART_PIC32
|
||||
bool "Microchip PIC32"
|
||||
depends on PIC32_SERIAL
|
||||
help
|
||||
Select this to enable a debug UART using the serial_pic32 driver. You
|
||||
will need to provide parameters to make this work. The driver will
|
||||
be available until the real driver model serial is running.
|
||||
|
||||
endchoice
|
||||
|
||||
config DEBUG_UART_BASE
|
||||
|
@ -241,6 +249,13 @@ config FSL_LPUART
|
|||
Select this to enable a Low Power UART for Freescale VF610 and
|
||||
QorIQ Layerscape devices.
|
||||
|
||||
config PIC32_SERIAL
|
||||
bool "Support for Microchip PIC32 on-chip UART"
|
||||
depends on DM_SERIAL && MACH_PIC32
|
||||
default y
|
||||
help
|
||||
Support for the UART found on Microchip PIC32 SoC's.
|
||||
|
||||
config SYS_NS16550
|
||||
bool "NS16550 UART or compatible"
|
||||
help
|
||||
|
|
|
@ -41,6 +41,7 @@ obj-$(CONFIG_MXS_AUART) += mxs_auart.o
|
|||
obj-$(CONFIG_ARC_SERIAL) += serial_arc.o
|
||||
obj-$(CONFIG_UNIPHIER_SERIAL) += serial_uniphier.o
|
||||
obj-$(CONFIG_STM32_SERIAL) += serial_stm32.o
|
||||
obj-$(CONFIG_PIC32_SERIAL) += serial_pic32.o
|
||||
|
||||
ifndef CONFIG_SPL_BUILD
|
||||
obj-$(CONFIG_USB_TTY) += usbtty.o
|
||||
|
|
198
drivers/serial/serial_pic32.c
Normal file
198
drivers/serial/serial_pic32.c
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* (c) 2015 Paul Thacker <paul.thacker@microchip.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <serial.h>
|
||||
#include <wait_bit.h>
|
||||
#include <mach/pic32.h>
|
||||
#include <dt-bindings/clock/microchip,clock.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/* UART Control Registers */
|
||||
#define U_MOD 0x00
|
||||
#define U_MODCLR (U_MOD + _CLR_OFFSET)
|
||||
#define U_MODSET (U_MOD + _SET_OFFSET)
|
||||
#define U_STA 0x10
|
||||
#define U_STACLR (U_STA + _CLR_OFFSET)
|
||||
#define U_STASET (U_STA + _SET_OFFSET)
|
||||
#define U_TXR 0x20
|
||||
#define U_RXR 0x30
|
||||
#define U_BRG 0x40
|
||||
|
||||
/* U_MOD bits */
|
||||
#define UART_ENABLE BIT(15)
|
||||
|
||||
/* U_STA bits */
|
||||
#define UART_RX_ENABLE BIT(12)
|
||||
#define UART_TX_BRK BIT(11)
|
||||
#define UART_TX_ENABLE BIT(10)
|
||||
#define UART_TX_FULL BIT(9)
|
||||
#define UART_TX_EMPTY BIT(8)
|
||||
#define UART_RX_OVER BIT(1)
|
||||
#define UART_RX_DATA_AVAIL BIT(0)
|
||||
|
||||
struct pic32_uart_priv {
|
||||
void __iomem *base;
|
||||
ulong uartclk;
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize the serial port with the given baudrate.
|
||||
* The settings are always 8 data bits, no parity, 1 stop bit, no start bits.
|
||||
*/
|
||||
static int pic32_serial_init(void __iomem *base, ulong clk, u32 baudrate)
|
||||
{
|
||||
u32 div = DIV_ROUND_CLOSEST(clk, baudrate * 16);
|
||||
|
||||
/* wait for TX FIFO to empty */
|
||||
wait_for_bit(__func__, base + U_STA, UART_TX_EMPTY,
|
||||
true, CONFIG_SYS_HZ, false);
|
||||
|
||||
/* send break */
|
||||
writel(UART_TX_BRK, base + U_STASET);
|
||||
|
||||
/* disable and clear mode */
|
||||
writel(0, base + U_MOD);
|
||||
writel(0, base + U_STA);
|
||||
|
||||
/* set baud rate generator */
|
||||
writel(div - 1, base + U_BRG);
|
||||
|
||||
/* enable the UART for TX and RX */
|
||||
writel(UART_TX_ENABLE | UART_RX_ENABLE, base + U_STASET);
|
||||
|
||||
/* enable the UART */
|
||||
writel(UART_ENABLE, base + U_MODSET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check whether any char pending in RX fifo */
|
||||
static int pic32_uart_pending_input(void __iomem *base)
|
||||
{
|
||||
/* check if rx buffer overrun error has occurred */
|
||||
if (readl(base + U_STA) & UART_RX_OVER) {
|
||||
readl(base + U_RXR);
|
||||
|
||||
/* clear overrun error to keep receiving */
|
||||
writel(UART_RX_OVER, base + U_STACLR);
|
||||
}
|
||||
|
||||
/* In PIC32 there is no way to know number of outstanding
|
||||
* chars in rx-fifo. Only it can be known whether there is any.
|
||||
*/
|
||||
return readl(base + U_STA) & UART_RX_DATA_AVAIL;
|
||||
}
|
||||
|
||||
static int pic32_uart_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct pic32_uart_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (input)
|
||||
return pic32_uart_pending_input(priv->base);
|
||||
|
||||
return !(readl(priv->base + U_STA) & UART_TX_EMPTY);
|
||||
}
|
||||
|
||||
static int pic32_uart_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct pic32_uart_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return pic32_serial_init(priv->base, priv->uartclk, baudrate);
|
||||
}
|
||||
|
||||
static int pic32_uart_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct pic32_uart_priv *priv = dev_get_priv(dev);
|
||||
|
||||
/* Check if Tx FIFO is full */
|
||||
if (readl(priv->base + U_STA) & UART_TX_FULL)
|
||||
return -EAGAIN;
|
||||
|
||||
/* pump the char to tx buffer */
|
||||
writel(ch, priv->base + U_TXR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pic32_uart_getc(struct udevice *dev)
|
||||
{
|
||||
struct pic32_uart_priv *priv = dev_get_priv(dev);
|
||||
|
||||
/* return error if RX fifo is empty */
|
||||
if (!pic32_uart_pending_input(priv->base))
|
||||
return -EAGAIN;
|
||||
|
||||
/* read the character from rx buffer */
|
||||
return readl(priv->base + U_RXR) & 0xff;
|
||||
}
|
||||
|
||||
static int pic32_uart_probe(struct udevice *dev)
|
||||
{
|
||||
struct pic32_uart_priv *priv = dev_get_priv(dev);
|
||||
struct udevice *clkdev;
|
||||
fdt_addr_t addr;
|
||||
fdt_size_t size;
|
||||
int ret;
|
||||
|
||||
/* get address */
|
||||
addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg", &size);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
priv->base = ioremap(addr, size);
|
||||
|
||||
/* get clock rate */
|
||||
ret = clk_get_by_index(dev, 0, &clkdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
priv->uartclk = clk_get_periph_rate(clkdev, ret);
|
||||
|
||||
/* initialize serial */
|
||||
return pic32_serial_init(priv->base, priv->uartclk, CONFIG_BAUDRATE);
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops pic32_uart_ops = {
|
||||
.putc = pic32_uart_putc,
|
||||
.pending = pic32_uart_pending,
|
||||
.getc = pic32_uart_getc,
|
||||
.setbrg = pic32_uart_setbrg,
|
||||
};
|
||||
|
||||
static const struct udevice_id pic32_uart_ids[] = {
|
||||
{ .compatible = "microchip,pic32mzda-uart" },
|
||||
{}
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(pic32_serial) = {
|
||||
.name = "pic32-uart",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = pic32_uart_ids,
|
||||
.probe = pic32_uart_probe,
|
||||
.ops = &pic32_uart_ops,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
.priv_auto_alloc_size = sizeof(struct pic32_uart_priv),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART_PIC32
|
||||
#include <debug_uart.h>
|
||||
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
pic32_serial_init(base, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
writel(ch, CONFIG_DEBUG_UART_BASE + U_TXR);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
#endif
|
168
include/configs/pic32mzdask.h
Normal file
168
include/configs/pic32mzdask.h
Normal file
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* (c) 2015 Purna Chandra Mandal <purna.mandal@microchip.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
* Microchip PIC32MZ[DA] Starter Kit.
|
||||
*/
|
||||
|
||||
#ifndef __PIC32MZDASK_CONFIG_H
|
||||
#define __PIC32MZDASK_CONFIG_H
|
||||
|
||||
/* System Configuration */
|
||||
#define CONFIG_SYS_TEXT_BASE 0x9d004000 /* .text */
|
||||
#define CONFIG_DISPLAY_BOARDINFO
|
||||
|
||||
/*--------------------------------------------
|
||||
* CPU configuration
|
||||
*/
|
||||
/* CPU Timer rate */
|
||||
#define CONFIG_SYS_MIPS_TIMER_FREQ 100000000
|
||||
|
||||
/* Cache Configuration */
|
||||
#define CONFIG_SYS_MIPS_CACHE_MODE CONF_CM_CACHABLE_NONCOHERENT
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
* Memory Layout
|
||||
*/
|
||||
#define CONFIG_SYS_SRAM_BASE 0x80000000
|
||||
#define CONFIG_SYS_SRAM_SIZE 0x00080000 /* 512K */
|
||||
|
||||
/* Initial RAM for temporary stack, global data */
|
||||
#define CONFIG_SYS_INIT_RAM_SIZE 0x10000
|
||||
#define CONFIG_SYS_INIT_RAM_ADDR \
|
||||
(CONFIG_SYS_SRAM_BASE + CONFIG_SYS_SRAM_SIZE - CONFIG_SYS_INIT_RAM_SIZE)
|
||||
#define CONFIG_SYS_INIT_SP_ADDR \
|
||||
(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_RAM_SIZE - 1)
|
||||
|
||||
/* SDRAM Configuration (for final code, data, stack, heap) */
|
||||
#define CONFIG_SYS_SDRAM_BASE 0x88000000
|
||||
#define CONFIG_SYS_MALLOC_LEN (256 << 10)
|
||||
#define CONFIG_SYS_BOOTPARAMS_LEN (4 << 10)
|
||||
#define CONFIG_STACKSIZE (4 << 10) /* regular stack */
|
||||
|
||||
#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE
|
||||
#define CONFIG_SYS_MONITOR_LEN (192 << 10)
|
||||
|
||||
#define CONFIG_SYS_LOAD_ADDR 0x88500000 /* default load address */
|
||||
#define CONFIG_SYS_ENV_ADDR 0x88300000
|
||||
#define CONFIG_SYS_FDT_ADDR 0x89d00000
|
||||
|
||||
/* Memory Test */
|
||||
#define CONFIG_SYS_MEMTEST_START 0x88000000
|
||||
#define CONFIG_SYS_MEMTEST_END 0x88080000
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
* Commands
|
||||
*/
|
||||
#define CONFIG_SYS_LONGHELP /* undef to save memory */
|
||||
#define CONFIG_CMD_CLK
|
||||
|
||||
/*-------------------------------------------------
|
||||
* FLASH configuration
|
||||
*/
|
||||
#define CONFIG_SYS_NO_FLASH
|
||||
|
||||
/*------------------------------------------------------------
|
||||
* Console Configuration
|
||||
*/
|
||||
#define CONFIG_BAUDRATE 115200
|
||||
#define CONFIG_SYS_CBSIZE 1024 /* Console I/O Buffer Size */
|
||||
#define CONFIG_SYS_MAXARGS 16 /* max number of command args*/
|
||||
#define CONFIG_SYS_PBSIZE \
|
||||
(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
|
||||
#define CONFIG_CMDLINE_EDITING 1
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Networking Configuration
|
||||
*/
|
||||
#define CONFIG_MII
|
||||
#define CONFIG_PHY_SMSC
|
||||
#define CONFIG_SYS_RX_ETH_BUFFER 8
|
||||
#define CONFIG_NET_RETRY_COUNT 20
|
||||
#define CONFIG_ARP_TIMEOUT 500 /* millisec */
|
||||
|
||||
#define CONFIG_CMD_MII
|
||||
|
||||
/*
|
||||
* BOOTP options
|
||||
*/
|
||||
#define CONFIG_BOOTP_BOOTFILESIZE
|
||||
#define CONFIG_BOOTP_BOOTPATH
|
||||
#define CONFIG_BOOTP_GATEWAY
|
||||
#define CONFIG_BOOTP_HOSTNAME
|
||||
|
||||
/*
|
||||
* Handover flattened device tree (dtb file) to Linux kernel
|
||||
*/
|
||||
#define CONFIG_OF_LIBFDT 1
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* SDHC Configuration
|
||||
*/
|
||||
#define CONFIG_SDHCI
|
||||
#define CONFIG_MMC
|
||||
#define CONFIG_GENERIC_MMC
|
||||
#define CONFIG_CMD_MMC
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* File System Configuration
|
||||
*/
|
||||
/* FAT FS */
|
||||
#define CONFIG_DOS_PARTITION
|
||||
#define CONFIG_PARTITION_UUIDS
|
||||
#define CONFIG_SUPPORT_VFAT
|
||||
#define CONFIG_FS_FAT
|
||||
#define CONFIG_FAT_WRITE
|
||||
#define CONFIG_CMD_FS_GENERIC
|
||||
#define CONFIG_CMD_PART
|
||||
#define CONFIG_CMD_FAT
|
||||
|
||||
/* EXT4 FS */
|
||||
#define CONFIG_FS_EXT4
|
||||
#define CONFIG_CMD_EXT2
|
||||
#define CONFIG_CMD_EXT4
|
||||
#define CONFIG_CMD_EXT4_WRITE
|
||||
|
||||
/* -------------------------------------------------
|
||||
* Environment
|
||||
*/
|
||||
#define CONFIG_ENV_IS_NOWHERE 1
|
||||
#define CONFIG_ENV_SIZE 0x4000
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* Board boot configuration
|
||||
*/
|
||||
#define CONFIG_TIMESTAMP /* Print image info with timestamp */
|
||||
#define CONFIG_BOOTDELAY 5
|
||||
|
||||
#define MEM_LAYOUT_ENV_SETTINGS \
|
||||
"kernel_addr_r="__stringify(CONFIG_SYS_LOAD_ADDR)"\0" \
|
||||
"fdt_addr_r="__stringify(CONFIG_SYS_FDT_ADDR)"\0" \
|
||||
"scriptaddr="__stringify(CONFIG_SYS_ENV_ADDR)"\0"
|
||||
|
||||
#define CONFIG_LEGACY_BOOTCMD_ENV \
|
||||
"legacy_bootcmd= " \
|
||||
"if load mmc 0 ${scriptaddr} uEnv.txt; then " \
|
||||
"env import -tr ${scriptaddr} ${filesize}; " \
|
||||
"if test -n \"${bootcmd_uenv}\" ; then " \
|
||||
"echo Running bootcmd_uenv ...; " \
|
||||
"run bootcmd_uenv; " \
|
||||
"fi; " \
|
||||
"fi; \0"
|
||||
|
||||
#define BOOT_TARGET_DEVICES(func) \
|
||||
func(MMC, mmc, 0) \
|
||||
func(DHCP, dhcp, na)
|
||||
|
||||
#include <config_distro_bootcmd.h>
|
||||
|
||||
#define CONFIG_EXTRA_ENV_SETTINGS \
|
||||
MEM_LAYOUT_ENV_SETTINGS \
|
||||
CONFIG_LEGACY_BOOTCMD_ENV \
|
||||
BOOTENV
|
||||
|
||||
#undef CONFIG_BOOTCOMMAND
|
||||
#define CONFIG_BOOTCOMMAND "run distro_bootcmd || run legacy_bootcmd"
|
||||
|
||||
#endif /* __PIC32MZDASK_CONFIG_H */
|
29
include/dt-bindings/clock/microchip,clock.h
Normal file
29
include/dt-bindings/clock/microchip,clock.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* (c) 2015 Purna Chandra Mandal <purna.mandal@microchip.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CLK_MICROCHIP_PIC32
|
||||
#define __CLK_MICROCHIP_PIC32
|
||||
|
||||
/* clock output indices */
|
||||
#define BASECLK 0
|
||||
#define PLLCLK 1
|
||||
#define MPLL 2
|
||||
#define SYSCLK 3
|
||||
#define PB1CLK 4
|
||||
#define PB2CLK 5
|
||||
#define PB3CLK 6
|
||||
#define PB4CLK 7
|
||||
#define PB5CLK 8
|
||||
#define PB6CLK 9
|
||||
#define PB7CLK 10
|
||||
#define REF1CLK 11
|
||||
#define REF2CLK 12
|
||||
#define REF3CLK 13
|
||||
#define REF4CLK 14
|
||||
#define REF5CLK 15
|
||||
|
||||
#endif /* __CLK_MICROCHIP_PIC32 */
|
Loading…
Reference in a new issue