diff options
author | br <br@FreeBSD.org> | 2014-02-02 17:48:06 +0000 |
---|---|---|
committer | br <br@FreeBSD.org> | 2014-02-02 17:48:06 +0000 |
commit | 837d437b96fceec35b53ed46044437e945e7afe5 (patch) | |
tree | f823af778a55c9702913e0148c25270e97345153 /sys/arm/freescale | |
parent | 76aed0fc5e0d9d386340dc4c40ce3b426e058886 (diff) | |
download | FreeBSD-src-837d437b96fceec35b53ed46044437e945e7afe5.zip FreeBSD-src-837d437b96fceec35b53ed46044437e945e7afe5.tar.gz |
o Expand device tree information
o Export iomuxc (pins) configuration to DTS
o Allow devices to assign clocks in DTS
Diffstat (limited to 'sys/arm/freescale')
-rw-r--r-- | sys/arm/freescale/vybrid/vf_ccm.c | 311 | ||||
-rw-r--r-- | sys/arm/freescale/vybrid/vf_iomuxc.c | 74 |
2 files changed, 359 insertions, 26 deletions
diff --git a/sys/arm/freescale/vybrid/vf_ccm.c b/sys/arm/freescale/vybrid/vf_ccm.c index 9a4ad2c..ce3e0bc 100644 --- a/sys/arm/freescale/vybrid/vf_ccm.c +++ b/sys/arm/freescale/vybrid/vf_ccm.c @@ -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]; @@ -125,6 +347,83 @@ ccm_probe(device_t dev) } 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) { struct ccm_softc *sc; @@ -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); } diff --git a/sys/arm/freescale/vybrid/vf_iomuxc.c b/sys/arm/freescale/vybrid/vf_iomuxc.c index 08daf5e..20b1fd1 100644 --- a/sys/arm/freescale/vybrid/vf_iomuxc.c +++ b/sys/arm/freescale/vybrid/vf_iomuxc.c @@ -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]; @@ -115,11 +111,62 @@ configure_pad(struct iomuxc_softc *sc, int pad, int mux_mode) } 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); } |