commit
d2427caf54
@ -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>; |
||||
}; |
||||
}; |
@ -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>; |
||||
}; |
||||
}; |
@ -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; |
@ -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 |
@ -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
|
@ -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 |
@ -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 */ |
@ -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__ */ |
@ -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) |
@ -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) |
||||
; |
||||
} |
@ -0,0 +1,13 @@ |
||||
|
||||
if TARGET_PIC32MZDASK |
||||
|
||||
config SYS_BOARD |
||||
default "pic32mzda" |
||||
|
||||
config SYS_VENDOR |
||||
default "microchip" |
||||
|
||||
config SYS_CONFIG_NAME |
||||
default "pic32mzdask" |
||||
|
||||
endif |
@ -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 |
@ -0,0 +1,7 @@ |
||||
#
|
||||
# (C) Copyright 2015
|
||||
# Purna Chandra Mandal, purna.mandal@microchip.com.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
obj-y := pic32mzda.o
|
@ -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. |
@ -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 |
@ -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 |
@ -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>; |
||||
}; |
@ -0,0 +1,5 @@ |
||||
* Microchip PIC32 serial UART |
||||
|
||||
Required properties: |
||||
- compatible: must be "microchip,pic32mzda-uart". |
||||
- reg: exactly one register range. |
@ -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), |
||||
}; |
@ -0,0 +1,6 @@ |
||||
#
|
||||
# Copyright (C) 2015 Microchip Technology Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
obj-$(CONFIG_MACH_PIC32) += ddr2.o
|
@ -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; |
||||
} |
@ -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 */ |
@ -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 */ |
@ -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), |
||||
}; |
@ -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), |
||||
}; |
@ -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), |
||||
}; |
@ -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_*/ |
@ -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); |
||||
} |
@ -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), |
||||
}; |
@ -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 |
@ -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 */ |
@ -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 new issue