o Expand device tree information

o Export iomuxc (pins) configuration to DTS
o Allow devices to assign clocks in DTS
This commit is contained in:
Ruslan Bukin 2014-02-02 17:48:06 +00:00
parent b4122742a6
commit bf636ac469
4 changed files with 583 additions and 35 deletions

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2013 Ruslan Bukin <br@bsdpad.com>
* Copyright (c) 2013-2014 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -73,8 +73,8 @@ __FBSDID("$FreeBSD$");
#define CCM_CCGRN 12
#define CCM_CCGR(n) (0x40 + (n * 0x04)) /* Clock Gating Register */
#define CCM_CMEOR(n) (0x70 + (n * 0x70)) /* Module Enable Override Reg */
#define CCM_CCPGR(n) (0x90 + (n * 0x04)) /* Platform Clock Gating Reg */
#define CCM_CMEOR(n) (0x70 + (n * 0x70)) /* Module Enable Override */
#define CCM_CCPGR(n) (0x90 + (n * 0x04)) /* Platform Clock Gating */
#define CCM_CPPDSR 0x88 /* PLL PFD Disable Status Register */
#define CCM_CCOWR 0x8C /* CORE Wakeup Register */
@ -100,6 +100,228 @@ __FBSDID("$FreeBSD$");
/* CCM_CSCDR1 */
#define ENET_TS_EN (1 << 23)
#define RMII_CLK_EN (1 << 24)
#define SAI3_EN (1 << 19)
/* CCM_CSCDR2 */
#define ESAI_EN (1 << 30)
#define ESDHC1_EN (1 << 29)
#define ESDHC0_EN (1 << 28)
#define NFC_EN (1 << 9)
#define ESDHC1_DIV_S 20
#define ESDHC1_DIV_M 0xf
#define ESDHC0_DIV_S 16
#define ESDHC0_DIV_M 0xf
/* CCM_CSCDR3 */
#define DCU0_EN (1 << 19)
#define QSPI1_EN (1 << 12)
#define QSPI1_DIV (1 << 11)
#define QSPI1_X2_DIV (1 << 10)
#define QSPI1_X4_DIV_M 0x3
#define QSPI1_X4_DIV_S 8
#define QSPI0_EN (1 << 4)
#define QSPI0_DIV (1 << 3)
#define QSPI0_X2_DIV (1 << 2)
#define QSPI0_X4_DIV_M 0x3
#define QSPI0_X4_DIV_S 0
#define SAI3_DIV_SHIFT 12
#define SAI3_DIV_MASK 0xf
#define ESAI_DIV_SHIFT 24
#define ESAI_DIV_MASK 0xf
#define PLL4_CLK_DIV_SHIFT 6
#define PLL4_CLK_DIV_MASK 0x7
#define IPG_CLK_DIV_SHIFT 11
#define IPG_CLK_DIV_MASK 0x3
#define ESAI_CLK_SEL_SHIFT 20
#define ESAI_CLK_SEL_MASK 0x3
#define SAI3_CLK_SEL_SHIFT 6
#define SAI3_CLK_SEL_MASK 0x3
#define CKO1_EN (1 << 10)
#define CKO1_DIV_MASK 0xf
#define CKO1_DIV_SHIFT 6
#define CKO1_SEL_MASK 0x3f
#define CKO1_SEL_SHIFT 0
#define CKO1_PLL4_MAIN 0x6
#define CKO1_PLL4_DIVD 0x7
struct clk {
uint32_t reg;
uint32_t enable_reg;
uint32_t div_mask;
uint32_t div_shift;
uint32_t div_val;
uint32_t sel_reg;
uint32_t sel_mask;
uint32_t sel_shift;
uint32_t sel_val;
};
/*
PLL4 clock divider (before switching the clocks should be gated)
000 Divide by 1 (only if PLL frequency less than or equal to 650 MHz)
001 Divide by 4
010 Divide by 6
011 Divide by 8
100 Divide by 10
101 Divide by 12
110 Divide by 14
111 Divide by 16
*/
static struct clk pll4_clk = {
.reg = CCM_CACRR,
.enable_reg = 0,
.div_mask = PLL4_CLK_DIV_MASK,
.div_shift = PLL4_CLK_DIV_SHIFT,
.div_val = 5, /* Divide by 12 */
.sel_reg = 0,
.sel_mask = 0,
.sel_shift = 0,
.sel_val = 0,
};
static struct clk sai3_clk = {
.reg = CCM_CSCDR1,
.enable_reg = SAI3_EN,
.div_mask = SAI3_DIV_MASK,
.div_shift = SAI3_DIV_SHIFT,
.div_val = 1,
.sel_reg = CCM_CSCMR1,
.sel_mask = SAI3_CLK_SEL_MASK,
.sel_shift = SAI3_CLK_SEL_SHIFT,
.sel_val = 0x3, /* Divided PLL4 main clock */
};
static struct clk cko1_clk = {
.reg = CCM_CCOSR,
.enable_reg = CKO1_EN,
.div_mask = CKO1_DIV_MASK,
.div_shift = CKO1_DIV_SHIFT,
.div_val = 1,
.sel_reg = CCM_CCOSR,
.sel_mask = CKO1_SEL_MASK,
.sel_shift = CKO1_SEL_SHIFT,
.sel_val = CKO1_PLL4_DIVD,
};
static struct clk esdhc0_clk = {
.reg = CCM_CSCDR2,
.enable_reg = ESDHC0_EN,
.div_mask = ESDHC0_DIV_M,
.div_shift = ESDHC0_DIV_S,
.div_val = 0x9,
.sel_reg = 0,
.sel_mask = 0,
.sel_shift = 0,
.sel_val = 0,
};
static struct clk esdhc1_clk = {
.reg = CCM_CSCDR2,
.enable_reg = ESDHC1_EN,
.div_mask = ESDHC1_DIV_M,
.div_shift = ESDHC1_DIV_S,
.div_val = 0x9,
.sel_reg = 0,
.sel_mask = 0,
.sel_shift = 0,
.sel_val = 0,
};
static struct clk qspi0_clk = {
.reg = CCM_CSCDR3,
.enable_reg = QSPI0_EN,
.div_mask = 0,
.div_shift = 0,
.div_val = 0,
.sel_reg = 0,
.sel_mask = 0,
.sel_shift = 0,
.sel_val = 0,
};
static struct clk dcu0_clk = {
.reg = CCM_CSCDR3,
.enable_reg = DCU0_EN,
.div_mask = 0x7,
.div_shift = 16, /* DCU0_DIV */
.div_val = 0, /* divide by 1 */
.sel_reg = 0,
.sel_mask = 0,
.sel_shift = 0,
.sel_val = 0,
};
static struct clk enet_clk = {
.reg = CCM_CSCDR1,
.enable_reg = (ENET_TS_EN | RMII_CLK_EN),
.div_mask = 0,
.div_shift = 0,
.div_val = 0,
.sel_reg = 0,
.sel_mask = 0,
.sel_shift = 0,
.sel_val = 0,
};
static struct clk nand_clk = {
.reg = CCM_CSCDR2,
.enable_reg = NFC_EN,
.div_mask = 0,
.div_shift = 0,
.div_val = 0,
.sel_reg = 0,
.sel_mask = 0,
.sel_shift = 0,
.sel_val = 0,
};
/*
Divider to generate ESAI clock
0000 Divide by 1
0001 Divide by 2
... ...
1111 Divide by 16
*/
static struct clk esai_clk = {
.reg = CCM_CSCDR2,
.enable_reg = ESAI_EN,
.div_mask = ESAI_DIV_MASK,
.div_shift = ESAI_DIV_SHIFT,
.div_val = 3, /* Divide by 4 */
.sel_reg = CCM_CSCMR1,
.sel_mask = ESAI_CLK_SEL_MASK,
.sel_shift = ESAI_CLK_SEL_SHIFT,
.sel_val = 0x3, /* Divided PLL4 main clock */
};
struct clock_entry {
char *name;
struct clk *clk;
};
static struct clock_entry clock_map[] = {
{"pll4", &pll4_clk},
{"sai3", &sai3_clk},
{"cko1", &cko1_clk},
{"esdhc0", &esdhc0_clk},
{"esdhc1", &esdhc1_clk},
{"qspi0", &qspi0_clk},
{"dcu0", &dcu0_clk},
{"enet", &enet_clk},
{"nand", &nand_clk},
{"esai", &esai_clk},
{NULL, NULL}
};
struct ccm_softc {
struct resource *res[1];
@ -124,6 +346,83 @@ ccm_probe(device_t dev)
return (BUS_PROBE_DEFAULT);
}
static int
set_clock(struct ccm_softc *sc, char *name)
{
struct clk *clk;
int reg;
int i;
for (i = 0; clock_map[i].name != NULL; i++) {
if (strcmp(clock_map[i].name, name) == 0) {
#if 0
device_printf(sc->dev, "Configuring %s clk\n", name);
#endif
clk = clock_map[i].clk;
if (clk->sel_reg != 0) {
reg = READ4(sc, clk->sel_reg);
reg &= ~(clk->sel_mask << clk->sel_shift);
reg |= (clk->sel_val << clk->sel_shift);
WRITE4(sc, clk->sel_reg, reg);
};
reg = READ4(sc, clk->reg);
reg |= clk->enable_reg;
reg &= ~(clk->div_mask << clk->div_shift);
reg |= (clk->div_val << clk->div_shift);
WRITE4(sc, clk->reg, reg);
};
};
return (0);
}
static int
ccm_fdt_set(struct ccm_softc *sc)
{
phandle_t child, parent, root;
int len;
char *fdt_config, *name;
root = OF_finddevice("/");
len = 0;
parent = root;
/* Find 'clock_names' prop in the tree */
for (child = OF_child(parent); child != 0; child = OF_peer(child)) {
/* Find a 'leaf'. Start the search from this node. */
while (OF_child(child)) {
parent = child;
child = OF_child(child);
}
if (!fdt_is_enabled(child))
continue;
if ((len = OF_getproplen(child, "clock_names")) > 0) {
len = OF_getproplen(child, "clock_names");
OF_getprop_alloc(child, "clock_names", 1,
(void **)&fdt_config);
while (len > 0) {
name = fdt_config;
fdt_config += strlen(name) + 1;
len -= strlen(name) + 1;
set_clock(sc, name);
};
};
if (OF_peer(child) == 0) {
/* No more siblings. */
child = parent;
parent = OF_parent(child);
}
}
return (0);
}
static int
ccm_attach(device_t dev)
{
@ -163,10 +462,8 @@ ccm_attach(device_t dev)
WRITE4(sc, CCM_CCGR(i), 0xffffffff);
}
/* Enable ENET clocks */
reg = READ4(sc, CCM_CSCDR1);
reg |= (ENET_TS_EN | RMII_CLK_EN);
WRITE4(sc, CCM_CSCDR1, reg);
/* Take and apply FDT clocks */
ccm_fdt_set(sc);
return (0);
}

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2013 Ruslan Bukin <br@bsdpad.com>
* Copyright (c) 2013-2014 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -67,16 +67,12 @@ __FBSDID("$FreeBSD$");
#define MUX_MODE_MASK 7
#define MUX_MODE_SHIFT 20
#define MUX_MODE_GPIO 0
#define MUX_MODE_RMII 1
#define MUX_MODE_RMII_CLKIN 2
#define MUX_MODE_VBUS_EN_OTG 2
#define PUS_22_KOHM_PULL_UP (3 << 4)
#define DSE_25_OHM (6 << 6)
#define NET0_PAD_START 45
#define NET1_PAD_START 54
#define NET_PAD_N 9
#define MAX_MUX_LEN 1024
struct iomuxc_softc {
struct resource *tmr_res[1];
@ -114,12 +110,63 @@ configure_pad(struct iomuxc_softc *sc, int pad, int mux_mode)
return (0);
}
static int
pinmux_set(struct iomuxc_softc *sc)
{
phandle_t child, parent, root;
pcell_t iomux_config[MAX_MUX_LEN];
int len;
int values;
int pin;
int mux_mode;
int i;
root = OF_finddevice("/");
len = 0;
parent = root;
/* Find 'iomux_config' prop in the nodes */
for (child = OF_child(parent); child != 0; child = OF_peer(child)) {
/* Find a 'leaf'. Start the search from this node. */
while (OF_child(child)) {
parent = child;
child = OF_child(child);
}
if (!fdt_is_enabled(child))
continue;
if ((len = OF_getproplen(child, "iomux_config")) > 0) {
OF_getprop(child, "iomux_config", &iomux_config, len);
values = len / (sizeof(uint32_t));
for (i = 0; i < values; i += 2) {
pin = fdt32_to_cpu(iomux_config[i]);
mux_mode = fdt32_to_cpu(iomux_config[i+1]);
#if 0
device_printf(sc->dev, "Set pin %d to ALT%d\n",
pin, mux_mode);
#endif
configure_pad(sc, IOMUXC(pin), mux_mode);
}
}
if (OF_peer(child) == 0) {
/* No more siblings. */
child = parent;
parent = OF_parent(child);
}
}
return (0);
}
static int
iomuxc_attach(device_t dev)
{
struct iomuxc_softc *sc;
int reg;
int i;
sc = device_get_softc(dev);
sc->dev = dev;
@ -138,18 +185,7 @@ iomuxc_attach(device_t dev)
reg = (PKE | PUE | PUS_22_KOHM_PULL_UP | DSE_25_OHM | OBE);
WRITE4(sc, IOMUXC_PTA7, reg);
/* NET */
configure_pad(sc, IOMUXC_PTA6, MUX_MODE_RMII_CLKIN);
/* NET0 */
for (i = NET0_PAD_START; i <= (NET0_PAD_START + NET_PAD_N); i++) {
configure_pad(sc, IOMUXC(i), MUX_MODE_RMII);
}
/* NET1 */
for (i = NET1_PAD_START; i <= (NET1_PAD_START + NET_PAD_N); i++) {
configure_pad(sc, IOMUXC(i), MUX_MODE_RMII);
}
pinmux_set(sc);
return (0);
}

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2013 Ruslan Bukin <br@bsdpad.com>
* Copyright (c) 2013-2014 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -39,12 +39,37 @@
};
SOC: vybrid {
serial0: serial@40027000 {
status = "disabled";
serial1: serial@40028000 {
status = "okay";
};
fec0: ethernet@400D0000 {
status = "disabled";
fec1: ethernet@400D1000 {
status = "okay";
iomux_config = < 54 0x1 55 0x1
56 0x1 57 0x1
58 0x1 59 0x1
60 0x1 61 0x1
62 0x1 0 0x2 >;
};
esai: esai@40062000 {
status = "okay";
};
edma1: edma@40098000 {
status = "okay";
};
tcon0: tcon@4003D000 {
status = "okay";
};
dcu0: dcu4@40058000 {
status = "okay";
};
adc0: adc@4003B000 {
status = "okay";
};
};

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2013 Ruslan Bukin <br@bsdpad.com>
* Copyright (c) 2013-2014 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -28,7 +28,7 @@
/ {
model = "Freescale Vybrid Family";
compatible = "freescale,vybrid", "fsl,vf";
compatible = "freescale,vybrid", "fsl,mvf";
#address-cells = <1>;
#size-cells = <1>;
@ -38,6 +38,15 @@
soc = &SOC;
serial0 = &serial0;
serial1 = &serial1;
sai0 = &sai0;
sai1 = &sai1;
sai2 = &sai2;
sai3 = &sai3;
esai = &esai;
adc0 = &adc0;
adc1 = &adc1;
edma0 = &edma0;
edma1 = &edma1;
src = &SRC;
};
@ -74,6 +83,7 @@
ccm@4006b000 {
compatible = "fsl,mvf600-ccm";
reg = <0x4006b000 0x1000>;
clock_names = "pll4";
};
mp_tmr@40002100 {
@ -87,6 +97,32 @@
interrupt-parent = < &GIC >;
};
dmamux@40024000 {
compatible = "fsl,mvf600-dmamux";
reg = <0x40024000 0x100>,
<0x40025000 0x100>,
<0x400A1000 0x100>,
<0x400A2000 0x100>;
};
edma0: edma@40018000 {
compatible = "fsl,mvf600-edma";
reg = <0x40018000 0x1000>,
<0x40019000 0x1000>; /* TCD */
interrupts = < 40 41 >;
interrupt-parent = <&GIC>;
status = "disabled";
};
edma1: edma@40098000 {
compatible = "fsl,mvf600-edma";
reg = <0x40098000 0x1000>,
<0x40099000 0x1000>; /* TCD */
interrupts = < 42 43 >;
interrupt-parent = <&GIC>;
status = "disabled";
};
pit@40037000 {
compatible = "fsl,mvf600-pit";
reg = <0x40037000 0x1000>;
@ -115,7 +151,6 @@
gpio-controller;
interrupts = < 139 140 141 142 143 >;
interrupt-parent = <&GIC>;
};
nand@400E0000 {
@ -125,6 +160,8 @@
reg = <0x400E0000 0x10000>;
interrupts = < 115 >;
interrupt-parent = <&GIC>;
clock_names = "nand";
status = "disabled";
partition@40000 {
reg = <0x40000 0x200000>; /* 2MB */
@ -146,7 +183,6 @@
reg = <0xe40000 0x1e000000>; /* 480MB */
label = "root";
};
};
sdhci0: sdhci@400B1000 {
@ -155,6 +191,8 @@
interrupts = < 59 >;
interrupt-parent = <&GIC>;
clock-frequency = <50000000>;
status = "disabled";
clock_names = "esdhc0";
};
sdhci1: sdhci@400B2000 {
@ -163,6 +201,11 @@
interrupts = < 60 >;
interrupt-parent = <&GIC>;
clock-frequency = <50000000>;
status = "disabled";
clock_names = "esdhc1";
iomux_config = < 14 0x5 15 0x5
16 0x5 17 0x5
18 0x5 19 0x5 >;
};
serial0: serial@40027000 {
@ -172,6 +215,7 @@
interrupt-parent = <&GIC>;
current-speed = <115200>;
clock-frequency = < 24000000 >;
status = "disabled";
};
serial1: serial@40028000 {
@ -181,6 +225,7 @@
interrupt-parent = <&GIC>;
current-speed = <115200>;
clock-frequency = < 24000000 >;
status = "disabled";
};
usb@40034000 {
@ -208,6 +253,13 @@
interrupt-parent = <&GIC>;
phy-mode = "rmii";
phy-disable-preamble;
status = "disabled";
clock_names = "enet";
iomux_config = < 45 0x1 46 0x1
47 0x1 48 0x1
49 0x1 50 0x1
51 0x1 52 0x1
53 0x1 >;
};
fec1: ethernet@400D1000 {
@ -217,7 +269,145 @@
interrupt-parent = <&GIC>;
phy-mode = "rmii";
phy-disable-preamble;
status = "disabled";
clock_names = "enet";
iomux_config = < 54 0x1 55 0x1
56 0x1 57 0x1
58 0x1 59 0x1
60 0x1 61 0x1
62 0x1 >;
};
sai0: sai@4002F000 {
compatible = "fsl,mvf600-sai";
reg = <0x4002F000 0x1000>;
interrupts = < 116 >;
interrupt-parent = <&GIC>;
status = "disabled";
};
sai1: sai@40030000 {
compatible = "fsl,mvf600-sai";
reg = <0x40030000 0x1000>;
interrupts = < 117 >;
interrupt-parent = <&GIC>;
status = "disabled";
};
sai2: sai@40031000 {
compatible = "fsl,mvf600-sai";
reg = <0x40031000 0x1000>;
interrupts = < 118 >;
interrupt-parent = <&GIC>;
status = "disabled";
};
sai3: sai@40032000 {
compatible = "fsl,mvf600-sai";
reg = <0x40032000 0x1000>;
interrupts = < 119 >;
interrupt-parent = <&GIC>;
status = "disabled";
clock_names = "sai3", "cko1";
iomux_config = < 16 0x2
19 0x2
21 0x2
40 0x4 >; /* CKO1 */
};
esai: esai@40062000 {
compatible = "fsl,mvf600-esai";
reg = <0x40062000 0x1000>;
interrupts = < 120 >;
interrupt-parent = <&GIC>;
status = "disabled";
clock_names = "esai";
iomux_config = < 45 0x4 46 0x4
47 0x4 48 0x4
49 0x4 50 0x4
51 0x4 52 0x4
78 0x3 40 0x4>;
};
spi0: spi@4002C000 {
compatible = "fsl,mvf600-spi";
reg = <0x4002C000 0x1000>;
interrupts = < 99 >;
interrupt-parent = <&GIC>;
status = "disabled";
iomux_config = < 40 0x1 41 0x1
42 0x1 43 0x1
44 0x1 >;
};
spi1: spi@4002D000 {
compatible = "fsl,mvf600-spi";
reg = <0x4002D000 0x1000>;
interrupts = < 100 >;
interrupt-parent = <&GIC>;
status = "disabled";
};
spi2: spi@400AC000 {
compatible = "fsl,mvf600-spi";
reg = <0x400AC000 0x1000>;
interrupts = < 101 >;
interrupt-parent = <&GIC>;
status = "disabled";
};
spi3: spi@400AD000 {
compatible = "fsl,mvf600-spi";
reg = <0x400AD000 0x1000>;
interrupts = < 102 >;
interrupt-parent = <&GIC>;
status = "disabled";
};
adc0: adc@4003B000 {
compatible = "fsl,mvf600-adc";
reg = <0x4003B000 0x1000>;
interrupts = < 85 >;
interrupt-parent = <&GIC>;
status = "disabled";
};
adc1: adc@400BB000 {
compatible = "fsl,mvf600-adc";
reg = <0x400BB000 0x1000>;
interrupts = < 86 >;
interrupt-parent = <&GIC>;
status = "disabled";
};
tcon0: tcon@4003D000 {
compatible = "fsl,mvf600-tcon";
reg = <0x4003D000 0x1000>;
status = "disabled";
};
dcu0: dcu4@40058000 {
compatible = "fsl,mvf600-dcu4";
reg = <0x40058000 0x7000>;
interrupts = < 62 >;
interrupt-parent = <&GIC>;
status = "disabled";
clock_names = "dcu0";
iomux_config = < 105 0x1 106 0x1
107 0x1 108 0x1
109 0x1 110 0x1
111 0x1 112 0x1
113 0x1 114 0x1
115 0x1 116 0x1
117 0x1 118 0x1
119 0x1 120 0x1
121 0x1 122 0x1
123 0x1 124 0x1
125 0x1 126 0x1
127 0x1 128 0x1
129 0x1 130 0x1
131 0x1 132 0x1
133 0x1 >;
};
};
};