net: Add Allwinner EMAC CLK, RESET support
Subsystems (5)
v2 cover net: Add Allwinner EMAC CLK, RESET support
This is v2 version for Allwinner EMAC CLK, RESET support, which was initially be a part of previous series[1].
Changes for v2:
- rebase on master
- add dm tests for new clk and reset functions.
Any inputs?
Jagan.
[1] https://patchwork.ozlabs.org/patch/959351/
Jagan Teki (13):
clk: sunxi: Implement A10 EMAC clocks
net: sunxi_emac: Add CLK support
net: sun8i_emac: Retrieve GMAC clock via 'syscon' phandle
clk: Get the CLK by index without device
clk: Use clk_get_by_index_tail()
test/dm: clk: Add clk_get_by_index[_nodev] test
reset: Get the RESET by index without device test/dm: reset: Add reset_get_by_index[_nodev] test
clk: sunxi: Implement EMAC, GMAC clocks, resets
net: sun8i_emac: Add CLK and RESET support
clk: sunxi: h3: Implement EPHY CLK and RESET
net: sun8i_emac: Add EPHY CLK and RESET support
board: sunxi: gmac: Remove Ethernet clock and reset
board/sunxi/gmac.c | 8 -- drivers/clk/clk-uclass.c | 84 +++++++++++----- drivers/clk/sunxi/clk_a10.c | 1 + drivers/clk/sunxi/clk_a10s.c | 1 + drivers/clk/sunxi/clk_a31.c | 2 + drivers/clk/sunxi/clk_a64.c | 2 + drivers/clk/sunxi/clk_a83t.c | 2 + drivers/clk/sunxi/clk_h3.c | 6 ++ drivers/clk/sunxi/clk_h6.c | 4 + drivers/clk/sunxi/clk_r40.c | 3 + drivers/net/sun8i_emac.c | 182 +++++++++++++++++++++++------------ drivers/net/sunxi_emac.c | 28 ++++-- drivers/reset/reset-uclass.c | 53 ++++++---- image.map | 4 + include/clk.h | 15 +++ include/reset.h | 16 +++ test/dm/clk.c | 21 ++++ test/dm/reset.c | 22 +++++ 18 files changed, 338 insertions(+), 116 deletions(-) create mode 100644 image.map
Signature · 1 line
2.18.0.321.gffc6fa0e3
PATCH v2 1/13 clk: sunxi: Implement A10 EMAC clocks
Implement EMAC clocks via ccu_clk_gate for Allwinner A10 SoC.
Which would eventually used in sunxi_emac.c driver.
--- drivers/clk/sunxi/clk_a10.c | 1 + drivers/clk/sunxi/clk_a10s.c | 1 + 2 files changed, 2 insertions(+)
drivers/clk/sunxi/clk_a10.c +1 -0
@@ -22,6 +22,7 @@ static struct ccu_clk_gate a10_gates[] = { [CLK_AHB_MMC1] = GATE(0x060, BIT(9)), [CLK_AHB_MMC2] = GATE(0x060, BIT(10)), [CLK_AHB_MMC3] = GATE(0x060, BIT(11)), + [CLK_AHB_EMAC] = GATE(0x060, BIT(17)), [CLK_AHB_SPI0] = GATE(0x060, BIT(20)), [CLK_AHB_SPI1] = GATE(0x060, BIT(21)), [CLK_AHB_SPI2] = GATE(0x060, BIT(22)),
drivers/clk/sunxi/clk_a10s.c +1 -0
@@ -19,6 +19,7 @@ static struct ccu_clk_gate a10s_gates[] = { [CLK_AHB_MMC0] = GATE(0x060, BIT(8)), [CLK_AHB_MMC1] = GATE(0x060, BIT(9)), [CLK_AHB_MMC2] = GATE(0x060, BIT(10)), + [CLK_AHB_EMAC] = GATE(0x060, BIT(17)), [CLK_AHB_SPI0] = GATE(0x060, BIT(20)), [CLK_AHB_SPI1] = GATE(0x060, BIT(21)), [CLK_AHB_SPI2] = GATE(0x060, BIT(22)),
Signature · 1 line
2.18.0.321.gffc6fa0e3
PATCH v2 2/13 net: sunxi_emac: Add CLK support
In reply to Jagan TekiAdd CLk support for sunxi_emac to enable AHB_EMAC clock via CLK framework.
--- drivers/net/sunxi_emac.c | 28 ++++++++++++++++++++++------ image.map | 4 ++++ 2 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 image.map
drivers/net/sunxi_emac.c +22 -6
@@ -6,6 +6,7 @@*/ #include <common.h> +#include <clk.h> #include <dm.h> #include <linux/err.h> #include <malloc.h>
@@ -157,6 +158,7 @@ struct sunxi_sramc_regs {struct emac_eth_dev {struct emac_regs *regs; +struct clk clk;struct mii_dev *bus;struct phy_device *phydev;int link_printed;
@@ -500,14 +502,12 @@ static int _sunxi_emac_eth_send(struct emac_eth_dev *priv, void *packet,return 0 ; } -static void sunxi_emac_board_setup (struct emac_eth_dev *priv) +static int sunxi_emac_board_setup (struct emac_eth_dev *priv) { -struct sunxi_ccm_reg *const ccm = - (struct sunxi_ccm_reg *)SUNXI_CCM_BASE ;struct sunxi_sramc_regs *sram = (struct sunxi_sramc_regs *)SUNXI_SRAMC_BASE ;struct emac_regs *regs = priv->regs; -int pin; +int pin, ret;/* Map SRAM to EMAC */ setbits_le32 (&sram->ctrl1,0x5 <<2 );
@@ -517,10 +517,16 @@ static void sunxi_emac_board_setup(struct emac_eth_dev *priv)sunxi_gpio_set_cfgpin (pin,SUNXI_GPA_EMAC );/* Set up clock gating */ -setbits_le32 (&ccm->ahb_gate0,0x1 <<AHB_GATE_OFFSET_EMAC ); + ret =clk_enable (&priv->clk); +if (ret) { +dev_err (dev,"failed to enable emac clock\n" ); +return ret; + }/* Set MII clock */ clrsetbits_le32 (®s->mac_mcfg,0xf <<2 ,0xd <<2 ); + +return 0 ; }static int sunxi_emac_eth_start (struct udevice *dev)
@@ -557,9 +563,19 @@ static int sunxi_emac_eth_probe(struct udevice *dev) {struct eth_pdata *pdata =dev_get_platdata (dev);struct emac_eth_dev *priv =dev_get_priv (dev); +int ret; priv->regs = (struct emac_regs *)pdata->iobase; -sunxi_emac_board_setup (priv); + + ret =clk_get_by_index (dev,0 , &priv->clk); +if (ret) { +dev_err (dev,"failed to get emac clock\n" ); +return ret; + } + + ret =sunxi_emac_board_setup (priv); +if (ret) +return ret;return sunxi_emac_init_phy (priv, dev); }
image.map new file +4 -0
@@ -0,0 +1,4 @@ +ImagePos Offset Size Name +00000000 00000000 0007050a main-section +00000000 00000000 00006000 blob +00008000 00008000 0006850a u-boot-img
Signature · 1 line
2.18.0.321.gffc6fa0e3
PATCH v2 3/13 net: sun8i_emac: Retrieve GMAC clock via 'syscon' phandle
In reply to Jagan TekiUnlike other Allwinner SoC's R40 GMAC clock control register is locate in CCU, but rest located via syscon itself. Since the phandle property for current code look for 'syscon' and it will grab the respective ccu or syscon base address based on DT property defined in respective SoC dtsi.
So, use the existing 'syscon' code even for R40 for retrieving GMAC clock via CCU and update the register directly in sun8i_emac_set_syscon instead of writing it separately using ccm base.
--- drivers/net/sun8i_emac.c | 55 ++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 28 deletions(-)
drivers/net/sun8i_emac.c +27 -28
@@ -285,10 +285,18 @@ static int sun8i_emac_set_syscon(struct sun8i_eth_pdata *pdata,int ret;u32 reg; - reg =readl (priv->sysctl_reg +0x30 ); +if (priv->variant ==R40_GMAC ) { +/* Select RGMII for R40 */ + reg =readl (priv->sysctl_reg +0x164 ); + reg |=CCM_GMAC_CTRL_TX_CLK_SRC_INT_RGMII | +CCM_GMAC_CTRL_GPIT_RGMII | +CCM_GMAC_CTRL_TX_CLK_DELAY (CONFIG_GMAC_TX_DELAY ); -if (priv->variant ==R40_GMAC ) +writel (reg, priv->sysctl_reg +0x164 );return 0 ; + } + + reg =readl (priv->sysctl_reg +0x30 );if (priv->variant ==H3_EMAC ) { ret =sun8i_emac_set_syscon_ephy (priv, ®);
@@ -662,13 +670,6 @@ static void sun8i_emac_board_setup(struct emac_eth_dev *priv)/* De-assert EMAC */ setbits_le32 (&ccm->ahb_gate1,BIT (AHB_GATE_OFFSET_GMAC )); - -/* Select RGMII for R40 */ -setbits_le32 (&ccm->gmac_clk_cfg, -CCM_GMAC_CTRL_TX_CLK_SRC_INT_RGMII | -CCM_GMAC_CTRL_GPIT_RGMII ); -setbits_le32 (&ccm->gmac_clk_cfg, -CCM_GMAC_CTRL_TX_CLK_DELAY (CONFIG_GMAC_TX_DELAY )); }else {/* Set clock gating for emac */ setbits_le32 (&ccm->ahb_gate0,BIT (AHB_GATE_OFFSET_GMAC ));
@@ -850,25 +851,23 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)return -EINVAL ; } -if (priv->variant !=R40_GMAC ) { - offset =fdtdec_lookup_phandle (gd->fdt_blob, node,"syscon" ); -if (offset <0 ) { -debug ("%s: cannot find syscon node\n" , __func__); -return -EINVAL ; - } - reg =fdt_getprop (gd->fdt_blob, offset,"reg" ,NULL ); -if (!reg) { -debug ("%s: cannot find reg property in syscon node\n" , - __func__); -return -EINVAL ; - } - priv->sysctl_reg =fdt_translate_address ((void *)gd->fdt_blob, - offset, reg); -if (priv->sysctl_reg ==FDT_ADDR_T_NONE ) { -debug ("%s: Cannot find syscon base address\n" , - __func__); -return -EINVAL ; - } + offset =fdtdec_lookup_phandle (gd->fdt_blob, node,"syscon" ); +if (offset <0 ) { +debug ("%s: cannot find syscon node\n" , __func__); +return -EINVAL ; + } + + reg =fdt_getprop (gd->fdt_blob, offset,"reg" ,NULL ); +if (!reg) { +debug ("%s: cannot find reg property in syscon node\n" , + __func__); +return -EINVAL ; + } + priv->sysctl_reg =fdt_translate_address ((void *)gd->fdt_blob, + offset, reg); +if (priv->sysctl_reg ==FDT_ADDR_T_NONE ) { +debug ("%s: Cannot find syscon base address\n" , __func__); +return -EINVAL ; } pdata->phy_interface =-1 ;
Signature · 1 line
2.18.0.321.gffc6fa0e3
PATCH v2 4/13 clk: Get the CLK by index without device
In reply to Jagan TekiGetting a CLK by index with device is not straight forward for some use-cases like handling clock operations for child node in parent driver. So we need to process the child node in parent probe via ofnode and process CLK operation for child without udevice but with ofnode.
So add clk_get_by_index_nodev() and move the common code in clk_get_by_index_tail() to use for clk_get_by_index()
--- drivers/clk/clk-uclass.c | 61 +++++++++++++++++++++++++++++++++++++++- include/clk.h | 15 ++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-)
drivers/clk/clk-uclass.c +60 -1
@@ -98,9 +98,68 @@ static int clk_get_by_indexed_prop(struct udevice *dev, const char *prop_name,return clk_request (dev_clk, clk); } +static int clk_get_by_index_tail (int ret,ofnode node, +struct ofnode_phandle_args *args, +const char *list_name,int index, +struct clk *clk) +{ +struct udevice *dev_clk; +const struct clk_ops *ops; + +assert (clk); + clk->dev =NULL ; +if (ret) + goto err; + + ret =uclass_get_device_by_ofnode (UCLASS_CLK , args->node, &dev_clk); +if (ret) { +debug ("%s: uclass_get_device_by_of_offset failed: err=%d\n" , + __func__, ret); +return ret; + } + + clk->dev = dev_clk; + + ops =clk_dev_ops (dev_clk); + +if (ops->of_xlate) + ret = ops->of_xlate (clk, args); +else + ret =clk_of_xlate_default (clk, args); +if (ret) { +debug ("of_xlate() failed: %d\n" , ret); +return ret; + } + +return clk_request (dev_clk, clk); +err: +debug ("%s: Node '%s', property '%s', failed to request CLK index %d: %d\n" , + __func__,ofnode_get_name (node), list_name, index, ret); +return ret; +} +int clk_get_by_index (struct udevice *dev,int index,struct clk *clk) { -return clk_get_by_indexed_prop (dev,"clocks" , index, clk); +struct ofnode_phandle_args args; +int ret; + + ret =dev_read_phandle_with_args (dev,"clocks" ,"#clock-cells" ,0 , + index, &args); + +return clk_get_by_index_tail (ret,dev_ofnode (dev), &args,"clocks" , + index >0 , clk); +} + +int clk_get_by_index_nodev (ofnode node,int index,struct clk *clk) +{ +struct ofnode_phandle_args args; +int ret; + + ret =ofnode_parse_phandle_with_args (node,"clocks" ,"#clock-cells" ,0 , + index >0 , &args); + +return clk_get_by_index_tail (ret, node, &args,"clocks" , + index >0 , clk); }int clk_get_bulk (struct udevice *dev,struct clk_bulk *bulk)
include/clk.h +15 -0
@@ -8,6 +8,7 @@#ifndef _CLK_H_#define _CLK_H_ +#include <dm/ofnode.h> #include <linux/errno.h> #include <linux/types.h>
@@ -100,6 +101,20 @@ int clk_get_by_index_platdata(struct udevice *dev, int index,*/ int clk_get_by_index (struct udevice *dev,int index,struct clk *clk); +/** +* clock_get_by_index_nodev - Get/request a clock by integer index +* without a device. +* +* This is a version of clk_get_by_index() that does not use a device. +* +* @node: The client ofnode. +* @index: The index of the clock to request, within the client's list of +* clocks. +* @clock A pointer to a clock struct to initialize. +* @return 0 if OK, or a negative error code. +*/ +int clk_get_by_index_nodev (ofnode node,int index,struct clk *clk); +/** * clock_get_bulk - Get/request all clocks of a device. *
Signature · 1 line
2.18.0.321.gffc6fa0e3
PATCH v2 4/13 clk: Get the CLK by index without device
Quoted 10 lines · Jagan Teki
Getting a CLK by index with device is not straight forward for some use-cases like handling clock operations for child node in parent driver. So we need to process the child node in parent probe via ofnode and process CLK operation for child without udevice but with ofnode.
So add
clk_get_by_index_nodev()and move the common code inclk_get_by_index_tail()to use forclk_get_by_index()
Quoted 8 lines
Cc Simon Glass <[email protected]>Cc Stephen Warren <[email protected]>Signed-off-by Jagan Teki <[email protected]>--- drivers/clk/clk-uclass.c | 61 +++++++++++++++++++++++++++++++++++++++- include/clk.h | 15 ++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-)
PATCH v2 5/13 clk: Use clk_get_by_index_tail()
In reply to Jagan Tekiclk_get_by_index_tail() now handle common clk get by index code so use it in relevant places.
--- drivers/clk/clk-uclass.c | 77 +++++++++++++--------------------------- 1 file changed, 25 insertions(+), 52 deletions(-)
drivers/clk/clk-uclass.c +25 -52
@@ -54,50 +54,6 @@ static int clk_of_xlate_default(struct clk *clk,return 0 ; } -static int clk_get_by_indexed_prop (struct udevice *dev,const char *prop_name, -int index,struct clk *clk) -{ -int ret; -struct ofnode_phandle_args args; -struct udevice *dev_clk; -const struct clk_ops *ops; - -debug ("%s(dev=%p, index=%d, clk=%p)\n" , __func__, dev, index, clk); - -assert (clk); - clk->dev =NULL ; - - ret =dev_read_phandle_with_args (dev, prop_name,"#clock-cells" ,0 , - index, &args); -if (ret) { -debug ("%s: fdtdec_parse_phandle_with_args failed: err=%d\n" , - __func__, ret); -return ret; - } - - ret =uclass_get_device_by_ofnode (UCLASS_CLK , args.node, &dev_clk); -if (ret) { -debug ("%s: uclass_get_device_by_of_offset failed: err=%d\n" , - __func__, ret); -return ret; - } - - clk->dev = dev_clk; - - ops =clk_dev_ops (dev_clk); - -if (ops->of_xlate) - ret = ops->of_xlate (clk, &args); -else - ret =clk_of_xlate_default (clk, &args); -if (ret) { -debug ("of_xlate() failed: %d\n" , ret); -return ret; - } - -return clk_request (dev_clk, clk); -} - static int clk_get_by_index_tail(int ret, ofnode node, struct ofnode_phandle_args *args, const char *list_name, int index,
@@ -197,10 +153,11 @@ bulk_get_err:static int clk_set_default_parents (struct udevice *dev) { +struct ofnode_phandle_args args;struct clk clk, parent_clk;int index;int num_parents; -int ret; +int ret, err; num_parents =dev_count_phandle_with_args (dev,"assigned-clock-parents" ,"#clock-cells" );
@@ -211,8 +168,13 @@ static int clk_set_default_parents(struct udevice *dev) }for (index =0 ; index < num_parents; index++) { - ret =clk_get_by_indexed_prop (dev,"assigned-clock-parents" , - index, &parent_clk); + err =dev_read_phandle_with_args (dev,"assigned-clock-parents" , +"#clock-cells" ,0 , + index, &args); + + ret =clk_get_by_index_tail (err,dev_ofnode (dev), &args, +"assigned-clock-parents" , + index >0 , &parent_clk);/* If -ENOENT, this is a no-op entry */ if (ret == -ENOENT )continue ;
@@ -223,8 +185,13 @@ static int clk_set_default_parents(struct udevice *dev)return ret; } - ret =clk_get_by_indexed_prop (dev,"assigned-clocks" , - index, &clk); + err =dev_read_phandle_with_args (dev,"assigned-clocks" , +"#clock-cells" ,0 , + index, &args); + + ret =clk_get_by_index_tail (err,dev_ofnode (dev), &args, +"assigned-clocks" , + index >0 , &clk);if (ret) {debug ("%s: could not get assigned clock %d for %s\n" , __func__, index,dev_read_name (dev));
@@ -252,11 +219,12 @@ static int clk_set_default_parents(struct udevice *dev)static int clk_set_default_rates (struct udevice *dev) { +struct ofnode_phandle_args args;struct clk clk;int index;int num_rates;int size; -int ret =0 ; +int err, ret =0 ;u32 *rates =NULL ; size =dev_read_size (dev,"assigned-clock-rates" );
@@ -277,8 +245,13 @@ static int clk_set_default_rates(struct udevice *dev)if (!rates[index])continue ; - ret =clk_get_by_indexed_prop (dev,"assigned-clocks" , - index, &clk); + err =dev_read_phandle_with_args (dev,"assigned-clocks" , +"#clock-cells" ,0 , + index, &args); + + ret =clk_get_by_index_tail (err,dev_ofnode (dev), &args, +"assigned-clocks" , + index >0 , &clk);if (ret) {debug ("%s: could not get assigned clock %d for %s\n" , __func__, index,dev_read_name (dev));
Signature · 1 line
2.18.0.321.gffc6fa0e3
PATCH v2 5/13 clk: Use clk_get_by_index_tail()
Hi Jagan,
Quoted 11 lines · Jagan Teki
clk_get_by_index_tail()now handle common clk get by index code so use it in relevant places.Cc Stephen Warren <[email protected]>Signed-off-by Jagan Teki <[email protected]>Reviewed-by Simon Glass <[email protected]>--- drivers/clk/clk-uclass.c | 77 +++++++++++++--------------------------- 1 file changed, 25 insertions(+), 52 deletions(-)
BTW you could keep clk_get_by_indexed_prop() and make it call those two functions I think.
Regards,
Simon
PATCH v2 6/13 test/dm: clk: Add clk_get_by_index[_nodev] test
In reply to Jagan TekiAdd sample dm clk test for clk_get_by_index andclk_get_by_index_nodev functionality code.
--- test/dm/clk.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
test/dm/clk.c +21 -0
@@ -4,12 +4,33 @@*/ #include <common.h> +#include <clk.h> #include <dm.h> #include <asm/clk.h> #include <dm/test.h> #include <linux/err.h> #include <test/ut.h> +/* Base test of the clk uclass */ +static int dm_test_clk_base (struct unit_test_state *uts) +{ +struct udevice *dev; +struct clk clk_method1; +struct clk clk_method2; + +/* Get the device using the clk device */ +ut_assertok (uclass_get_device_by_name (UCLASS_MISC ,"clk-test" , &dev)); + +/* Get the same clk port in 2 different ways and compare */ +ut_assertok (clk_get_by_index (dev,1 , &clk_method1)); +ut_assertok (clk_get_by_index_nodev (dev_ofnode (dev),1 , &clk_method2)); +ut_asserteq (clk_method1.id, clk_method2.id); + +return 0 ; +} + +DM_TEST (dm_test_clk_base,DM_TESTF_SCAN_FDT ); +static int dm_test_clk (struct unit_test_state *uts) {struct udevice *dev_fixed, *dev_clk, *dev_test;
Signature · 1 line
2.18.0.321.gffc6fa0e3
PATCH v2 6/13 test/dm: clk: Add clk_get_by_index[_nodev] test
Quoted 10 lines · Jagan Teki
Add sample dm clk test for
clk_get_by_indexandclk_get_by_index_nodevfunctionality code.Cc Stephen Warren <[email protected]>Cc Simon Glass <[email protected]>Signed-off-by Jagan Teki <[email protected]>--- test/dm/clk.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
PATCH v2 7/13 reset: Get the RESET by index without device
In reply to Jagan TekiGetting a RESET by index with device is not straight forward for some use-cases like handling clock operations for child node in parent driver. So we need to process the child node in parent probe via ofnode and process RESET operation for child without udevice but with ofnode.
So add reset_get_by_index_nodev() and move the common code in reset_get_by_index_tail() to use for reset_get_by_index()
--- drivers/reset/reset-uclass.c | 53 ++++++++++++++++++++++++------------ include/reset.h | 16 +++++++++++ 2 files changed, 52 insertions(+), 17 deletions(-)
drivers/reset/reset-uclass.c +36 -17
@@ -29,41 +29,34 @@ static int reset_of_xlate_default(struct reset_ctl *reset_ctl,return 0 ; } -int reset_get_by_index (struct udevice *dev,int index, -struct reset_ctl *reset_ctl) +static int reset_get_by_index_tail (int ret,ofnode node, +struct ofnode_phandle_args *args, +const char *list_name,int index, +struct reset_ctl *reset_ctl) { -struct ofnode_phandle_args args; -int ret;struct udevice *dev_reset;struct reset_ops *ops; -debug ("%s(dev=%p, index=%d, reset_ctl=%p)\n" , __func__, dev, index, - reset_ctl); +assert (reset_ctl); reset_ctl->dev =NULL ; - - ret =dev_read_phandle_with_args (dev,"resets" ,"#reset-cells" ,0 , - index, &args); -if (ret) { -debug ("%s: fdtdec_parse_phandle_with_args() failed: %d\n" , - __func__, ret); +if (ret)return ret; - } - ret =uclass_get_device_by_ofnode (UCLASS_RESET , args.node, + ret =uclass_get_device_by_ofnode (UCLASS_RESET , args->node, &dev_reset);if (ret) {debug ("%s: uclass_get_device_by_ofnode() failed: %d\n" , __func__, ret); -debug ("%s %d\n" ,ofnode_get_name (args.node), args.args[0 ]); +debug ("%s %d\n" ,ofnode_get_name (args->node), args->args[0 ]);return ret; } ops =reset_dev_ops (dev_reset); reset_ctl->dev = dev_reset;if (ops->of_xlate) - ret = ops->of_xlate (reset_ctl, &args); + ret = ops->of_xlate (reset_ctl, args);else - ret =reset_of_xlate_default (reset_ctl, &args); + ret =reset_of_xlate_default (reset_ctl, args);if (ret) {debug ("of_xlate() failed: %d\n" , ret);return ret;
@@ -78,6 +71,32 @@ int reset_get_by_index(struct udevice *dev, int index,return 0 ; } +int reset_get_by_index (struct udevice *dev,int index, +struct reset_ctl *reset_ctl) +{ +struct ofnode_phandle_args args; +int ret; + + ret =dev_read_phandle_with_args (dev,"resets" ,"#reset-cells" ,0 , + index, &args); + +return reset_get_by_index_tail (ret,dev_ofnode (dev), &args,"resets" , + index >0 , reset_ctl); +} + +int reset_get_by_index_nodev (ofnode node,int index, +struct reset_ctl *reset_ctl) +{ +struct ofnode_phandle_args args; +int ret; + + ret =ofnode_parse_phandle_with_args (node,"resets" ,"#reset-cells" ,0 , + index >0 , &args); + +return reset_get_by_index_tail (ret, node, &args,"resets" , + index >0 , reset_ctl); +} +int reset_get_bulk (struct udevice *dev,struct reset_ctl_bulk *bulk) {int i, ret, err, count;
include/reset.h +16 -0
@@ -6,6 +6,7 @@#ifndef _RESET_H#define _RESET_H +#include <dm/ofnode.h> #include <linux/errno.h> /**
@@ -99,6 +100,21 @@ struct reset_ctl_bulk {int reset_get_by_index (struct udevice *dev,int index,struct reset_ctl *reset_ctl); +/** +* reset_get_by_index_nodev - Get/request a reset signal by integer index +* without a device. +* +* This is a version of reset_get_by_index() that does not use a device. +* +* @node: The client ofnode. +* @index: The index of the reset signal to request, within the client's +* list of reset signals. +* @reset_ctl A pointer to a reset control struct to initialize. +* @return 0 if OK, or a negative error code. +*/ +int reset_get_by_index_nodev (ofnode node,int index, +struct reset_ctl *reset_ctl); +/** * reset_get_bulk - Get/request all reset signals of a device. *
Signature · 1 line
2.18.0.321.gffc6fa0e3
PATCH v2 7/13 reset: Get the RESET by index without device
Quoted 10 lines · Jagan Teki
Getting a RESET by index with device is not straight forward for some use-cases like handling clock operations for child node in parent driver. So we need to process the child node in parent probe via ofnode and process RESET operation for child without udevice but with ofnode.
So add
reset_get_by_index_nodev()and move the common code inreset_get_by_index_tail()to use forreset_get_by_index()
Quoted 7 lines
Cc Stephen Warren <[email protected]>Cc Simon Glass <[email protected]>Signed-off-by Jagan Teki <[email protected]>--- drivers/reset/reset-uclass.c | 53 ++++++++++++++++++++++++------------ include/reset.h | 16 +++++++++++ 2 files changed, 52 insertions(+), 17 deletions(-)
PATCH v2 8/13 test/dm: reset: Add reset_get_by_index[_nodev] test
In reply to Jagan TekiAdd sample dm reset test for reset_get_by_index and reset_get_by_index_nodev functionality code.
--- test/dm/reset.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
test/dm/reset.c +22 -0
@@ -5,6 +5,7 @@#include <common.h> #include <dm.h> +#include <reset.h> #include <dm/test.h> #include <asm/reset.h> #include <test/ut.h>
@@ -15,6 +16,27 @@/* This is the other reset phandle specifier handled by bulk */ #define OTHER_RESET_ID 2 +/* Base test of the reset uclass */ +static int dm_test_reset_base (struct unit_test_state *uts) +{ +struct udevice *dev; +struct reset_ctl reset_method1; +struct reset_ctl reset_method2; + +/* Get the device using the reset device */ +ut_assertok (uclass_get_device_by_name (UCLASS_MISC ,"reset-ctl-test" , + &dev)); + +/* Get the same reset port in 2 different ways and compare */ +ut_assertok (reset_get_by_index (dev,1 , &reset_method1)); +ut_assertok (reset_get_by_index_nodev (dev_ofnode (dev),1 , &reset_method2)); +ut_asserteq (reset_method1.id, reset_method2.id); + +return 0 ; +} + +DM_TEST (dm_test_reset_base,DM_TESTF_SCAN_FDT ); +static int dm_test_reset (struct unit_test_state *uts) {struct udevice *dev_reset;
Signature · 1 line
2.18.0.321.gffc6fa0e3
PATCH v2 8/13 test/dm: reset: Add reset_get_by_index[_nodev] test
Quoted 11 lines · Jagan Teki
Add sample dm reset test for
reset_get_by_indexandreset_get_by_index_nodevfunctionality code.Cc Stephen Warren <[email protected]>Cc Simon Glass <[email protected]>Signed-off-by Jagan Teki <[email protected]>--- test/dm/reset.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
PATCH v2 9/13 clk: sunxi: Implement EMAC, GMAC clocks, resets
In reply to Jagan Teki- Implement EMAC, GMAC clocks via ccu_clk_gate for all supported Allwinner SoCs.
- Implement EMAC, GMAC resets via ccu_reset for all supported Allwinner SoCs.
--- drivers/clk/sunxi/clk_a31.c | 2 ++ drivers/clk/sunxi/clk_a64.c | 2 ++ drivers/clk/sunxi/clk_a83t.c | 2 ++ drivers/clk/sunxi/clk_h3.c | 2 ++ drivers/clk/sunxi/clk_h6.c | 4 ++++ drivers/clk/sunxi/clk_r40.c | 3 +++ 6 files changed, 15 insertions(+)
drivers/clk/sunxi/clk_a31.c +2 -0
@@ -17,6 +17,7 @@ static struct ccu_clk_gate a31_gates[] = { [CLK_AHB1_MMC1] = GATE(0x060, BIT(9)), [CLK_AHB1_MMC2] = GATE(0x060, BIT(10)), [CLK_AHB1_MMC3] = GATE(0x060, BIT(11)), + [CLK_AHB1_EMAC] = GATE(0x060, BIT(17)), [CLK_AHB1_SPI0] = GATE(0x060, BIT(20)), [CLK_AHB1_SPI1] = GATE(0x060, BIT(21)), [CLK_AHB1_SPI2] = GATE(0x060, BIT(22)),
@@ -57,6 +58,7 @@ static struct ccu_reset a31_resets[] = { [RST_AHB1_MMC1] = RESET(0x2c0, BIT(9)), [RST_AHB1_MMC2] = RESET(0x2c0, BIT(10)), [RST_AHB1_MMC3] = RESET(0x2c0, BIT(11)), + [RST_AHB1_EMAC] = RESET(0x2c0, BIT(17)), [RST_AHB1_SPI0] = RESET(0x2c0, BIT(20)), [RST_AHB1_SPI1] = RESET(0x2c0, BIT(21)), [RST_AHB1_SPI2] = RESET(0x2c0, BIT(22)),
drivers/clk/sunxi/clk_a64.c +2 -0
@@ -16,6 +16,7 @@ static const struct ccu_clk_gate a64_gates[] = { [CLK_BUS_MMC0] = GATE(0x060, BIT(8)), [CLK_BUS_MMC1] = GATE(0x060, BIT(9)), [CLK_BUS_MMC2] = GATE(0x060, BIT(10)), + [CLK_BUS_EMAC] = GATE(0x060, BIT(17)), [CLK_BUS_SPI0] = GATE(0x060, BIT(20)), [CLK_BUS_SPI1] = GATE(0x060, BIT(21)), [CLK_BUS_OTG] = GATE(0x060, BIT(23)),
@@ -49,6 +50,7 @@ static const struct ccu_reset a64_resets[] = { [RST_BUS_MMC0] = RESET(0x2c0, BIT(8)), [RST_BUS_MMC1] = RESET(0x2c0, BIT(9)), [RST_BUS_MMC2] = RESET(0x2c0, BIT(10)), + [RST_BUS_EMAC] = RESET(0x2c0, BIT(17)), [RST_BUS_SPI0] = RESET(0x2c0, BIT(20)), [RST_BUS_SPI1] = RESET(0x2c0, BIT(21)), [RST_BUS_OTG] = RESET(0x2c0, BIT(23)),
drivers/clk/sunxi/clk_a83t.c +2 -0
@@ -16,6 +16,7 @@ static struct ccu_clk_gate a83t_gates[] = { [CLK_BUS_MMC0] = GATE(0x060, BIT(8)), [CLK_BUS_MMC1] = GATE(0x060, BIT(9)), [CLK_BUS_MMC2] = GATE(0x060, BIT(10)), + [CLK_BUS_EMAC] = GATE(0x060, BIT(17)), [CLK_BUS_SPI0] = GATE(0x060, BIT(20)), [CLK_BUS_SPI1] = GATE(0x060, BIT(21)), [CLK_BUS_OTG] = GATE(0x060, BIT(24)),
@@ -47,6 +48,7 @@ static struct ccu_reset a83t_resets[] = { [RST_BUS_MMC0] = RESET(0x2c0, BIT(8)), [RST_BUS_MMC1] = RESET(0x2c0, BIT(9)), [RST_BUS_MMC2] = RESET(0x2c0, BIT(10)), + [RST_BUS_EMAC] = RESET(0x2c0, BIT(17)), [RST_BUS_SPI0] = RESET(0x2c0, BIT(20)), [RST_BUS_SPI1] = RESET(0x2c0, BIT(21)), [RST_BUS_OTG] = RESET(0x2c0, BIT(24)),
drivers/clk/sunxi/clk_h3.c +2 -0
@@ -16,6 +16,7 @@ static struct ccu_clk_gate h3_gates[] = { [CLK_BUS_MMC0] = GATE(0x060, BIT(8)), [CLK_BUS_MMC1] = GATE(0x060, BIT(9)), [CLK_BUS_MMC2] = GATE(0x060, BIT(10)), + [CLK_BUS_EMAC] = GATE(0x060, BIT(17)), [CLK_BUS_SPI0] = GATE(0x060, BIT(20)), [CLK_BUS_SPI1] = GATE(0x060, BIT(21)), [CLK_BUS_OTG] = GATE(0x060, BIT(23)),
@@ -55,6 +56,7 @@ static struct ccu_reset h3_resets[] = { [RST_BUS_MMC0] = RESET(0x2c0, BIT(8)), [RST_BUS_MMC1] = RESET(0x2c0, BIT(9)), [RST_BUS_MMC2] = RESET(0x2c0, BIT(10)), + [RST_BUS_EMAC] = RESET(0x2c0, BIT(17)), [RST_BUS_SPI0] = RESET(0x2c0, BIT(20)), [RST_BUS_SPI1] = RESET(0x2c0, BIT(21)), [RST_BUS_OTG] = RESET(0x2c0, BIT(23)),
drivers/clk/sunxi/clk_h6.c +4 -0
@@ -26,6 +26,8 @@ static struct ccu_clk_gate h6_gates[] = { [CLK_BUS_SPI0] = GATE(0x96c, BIT(0)), [CLK_BUS_SPI1] = GATE(0x96c, BIT(1)), + + [CLK_BUS_EMAC] = GATE(0x97c, BIT(0)), };static struct ccu_reset h6_resets[] = {
@@ -39,6 +41,8 @@ static struct ccu_reset h6_resets[] = { [RST_BUS_SPI0] = RESET(0x96c, BIT(16)), [RST_BUS_SPI1] = RESET(0x96c, BIT(17)), + + [RST_BUS_EMAC] = RESET(0x97c, BIT(16)), };static const struct ccu_desc h6_ccu_desc = {
drivers/clk/sunxi/clk_r40.c +3 -0
@@ -29,6 +29,8 @@ static struct ccu_clk_gate r40_gates[] = { [CLK_BUS_OHCI1] = GATE(0x060, BIT(30)), [CLK_BUS_OHCI2] = GATE(0x060, BIT(31)), + [CLK_BUS_GMAC] = GATE(0x064, BIT(17)), + [CLK_BUS_UART0] = GATE(0x06c, BIT(16)), [CLK_BUS_UART1] = GATE(0x06c, BIT(17)), [CLK_BUS_UART2] = GATE(0x06c, BIT(18)),
@@ -60,6 +62,7 @@ static struct ccu_reset r40_resets[] = { [RST_BUS_MMC1] = RESET(0x2c0, BIT(9)), [RST_BUS_MMC2] = RESET(0x2c0, BIT(10)), [RST_BUS_MMC3] = RESET(0x2c0, BIT(11)), + [RST_BUS_GMAC] = RESET(0x2c0, BIT(17)), [RST_BUS_SPI0] = RESET(0x2c0, BIT(20)), [RST_BUS_SPI1] = RESET(0x2c0, BIT(21)), [RST_BUS_SPI2] = RESET(0x2c0, BIT(22)),
Signature · 1 line
2.18.0.321.gffc6fa0e3
PATCH v2 10/13 net: sun8i_emac: Add CLK and RESET support
In reply to Jagan TekiAdd CLK and RESET support for sun8i_emac driver to enable TX clock and reset pins via CLK and RESET framework.
--- drivers/net/sun8i_emac.c | 57 +++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 15 deletions(-)
drivers/net/sun8i_emac.c +42 -15
@@ -14,12 +14,14 @@#include <asm/arch/clock.h> #include <asm/arch/gpio.h> #include <common.h> +#include <clk.h> #include <dm.h> #include <fdt_support.h> #include <linux/err.h> #include <malloc.h> #include <miiphy.h> #include <net.h> +#include <reset.h> #include <dt-bindings/pinctrl/sun4i-a10.h> #ifdef CONFIG_DM_GPIO #include <asm-generic/gpio.h>
@@ -135,6 +137,8 @@ struct emac_eth_dev {phys_addr_t sysctl_reg;struct phy_device *phydev;struct mii_dev *bus; +struct clk tx_clk; +struct reset_ctl tx_rst;#ifdef CONFIG_DM_GPIO struct gpio_desc reset_gpio;#endif
@@ -647,9 +651,24 @@ static int sun8i_eth_write_hwaddr(struct udevice *dev)return _sun8i_write_hwaddr (priv, pdata->enetaddr); } -static void sun8i_emac_board_setup (struct emac_eth_dev *priv) +static int sun8i_emac_board_setup (struct emac_eth_dev *priv) {struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE ; +int ret; + + ret =clk_enable (&priv->tx_clk); +if (ret) { +dev_err (dev,"failed to enable TX clock\n" ); +return ret; + } + +if (reset_valid (&priv->tx_rst)) { + ret =reset_deassert (&priv->tx_rst); +if (ret) { +dev_err (dev,"failed to deassert TX reset\n" ); + goto err_tx_clk; + } + }if (priv->variant ==H3_EMAC ) {/* Only H3/H5 have clock controls for internal EPHY */
@@ -664,19 +683,11 @@ static void sun8i_emac_board_setup(struct emac_eth_dev *priv) } } -if (priv->variant ==R40_GMAC ) { -/* Set clock gating for emac */ -setbits_le32 (&ccm->ahb_reset1_cfg,BIT (AHB_RESET_OFFSET_GMAC )); - -/* De-assert EMAC */ -setbits_le32 (&ccm->ahb_gate1,BIT (AHB_GATE_OFFSET_GMAC )); - }else { -/* Set clock gating for emac */ -setbits_le32 (&ccm->ahb_gate0,BIT (AHB_GATE_OFFSET_GMAC )); +return 0 ; -/* De-assert EMAC */ -setbits_le32 (&ccm->ahb_reset0_cfg,BIT (AHB_RESET_OFFSET_GMAC )); - } +err_tx_clk: +clk_disable (&priv->tx_clk); +return ret; }#if defined(CONFIG_DM_GPIO )
@@ -803,10 +814,14 @@ static int sun8i_emac_eth_probe(struct udevice *dev)struct sun8i_eth_pdata *sun8i_pdata =dev_get_platdata (dev);struct eth_pdata *pdata = &sun8i_pdata->eth_pdata;struct emac_eth_dev *priv =dev_get_priv (dev); +int ret; priv->mac_reg = (void *)pdata->iobase; -sun8i_emac_board_setup (priv); + ret =sun8i_emac_board_setup (priv); +if (ret) +return ret; +sun8i_emac_set_syscon (sun8i_pdata, priv);sun8i_mdio_init (dev->name, dev);
@@ -835,8 +850,8 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)int offset =0 ;#ifdef CONFIG_DM_GPIO int reset_flags =GPIOD_IS_OUT ; -int ret =0 ;#endif +int ret; pdata->iobase =devfdt_get_addr (dev);if (pdata->iobase ==FDT_ADDR_T_NONE ) {
@@ -851,6 +866,18 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)return -EINVAL ; } + ret =clk_get_by_name (dev,"stmmaceth" , &priv->tx_clk); +if (ret) { +dev_err (dev,"failed to get TX clock\n" ); +return ret; + } + + ret =reset_get_by_name (dev,"stmmaceth" , &priv->tx_rst); +if (ret && ret != -ENOENT ) { +dev_err (dev,"failed to get TX reset\n" ); +return ret; + } + offset =fdtdec_lookup_phandle (gd->fdt_blob, node,"syscon" );if (offset <0 ) {debug ("%s: cannot find syscon node\n" , __func__);
Signature · 1 line
2.18.0.321.gffc6fa0e3
PATCH v2 11/13 clk: sunxi: h3: Implement EPHY CLK and RESET
In reply to Jagan TekiEPHY CLK and RESET is availble in Allwinner H3 EMAC via mdio-mux node of internal PHY. Add the respetive clock and reset reg and bits.
--- drivers/clk/sunxi/clk_h3.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/clk/sunxi/clk_h3.c +4 -0
@@ -34,6 +34,8 @@ static struct ccu_clk_gate h3_gates[] = { [CLK_BUS_UART2] = GATE(0x06c, BIT(18)), [CLK_BUS_UART3] = GATE(0x06c, BIT(19)), + [CLK_BUS_EPHY] = GATE(0x070, BIT(0)), + [CLK_SPI0] = GATE(0x0a0, BIT(31)), [CLK_SPI1] = GATE(0x0a4, BIT(31)),
@@ -69,6 +71,8 @@ static struct ccu_reset h3_resets[] = { [RST_BUS_OHCI2] = RESET(0x2c0, BIT(30)), [RST_BUS_OHCI3] = RESET(0x2c0, BIT(31)), + [RST_BUS_EPHY] = RESET(0x2c8, BIT(2)), + [RST_BUS_UART0] = RESET(0x2d8, BIT(16)), [RST_BUS_UART1] = RESET(0x2d8, BIT(17)), [RST_BUS_UART2] = RESET(0x2d8, BIT(18)),
Signature · 1 line
2.18.0.321.gffc6fa0e3
PATCH v2 12/13 net: sun8i_emac: Add EPHY CLK and RESET support
In reply to Jagan TekiAdd EPHY CLK and RESET support for sun8i_emac driver to enable EPHY TX clock and EPHY reset pins via CLK and RESET framework.
--- drivers/net/sun8i_emac.c | 72 ++++++++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 17 deletions(-)
drivers/net/sun8i_emac.c +55 -17
@@ -138,7 +138,9 @@ struct emac_eth_dev {struct phy_device *phydev;struct mii_dev *bus;struct clk tx_clk; +struct clk ephy_clk;struct reset_ctl tx_rst; +struct reset_ctl ephy_rst;#ifdef CONFIG_DM_GPIO struct gpio_desc reset_gpio;#endif
@@ -653,7 +655,6 @@ static int sun8i_eth_write_hwaddr(struct udevice *dev)static int sun8i_emac_board_setup (struct emac_eth_dev *priv) { -struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE ;int ret; ret =clk_enable (&priv->tx_clk);
@@ -670,16 +671,20 @@ static int sun8i_emac_board_setup(struct emac_eth_dev *priv) } } -if (priv->variant ==H3_EMAC ) { -/* Only H3/H5 have clock controls for internal EPHY */ -if (priv->use_internal_phy) { -/* Set clock gating for ephy */ -setbits_le32 (&ccm->bus_gate4, -BIT (AHB_GATE_OFFSET_EPHY )); - -/* Deassert EPHY */ -setbits_le32 (&ccm->ahb_reset2_cfg, -BIT (AHB_RESET_OFFSET_EPHY )); +/* Only H3/H5 have clock controls for internal EPHY */ +if (clk_valid (&priv->ephy_clk)) { + ret =clk_enable (&priv->ephy_clk); +if (ret) { +dev_err (dev,"failed to enable EPHY TX clock\n" ); +return ret; + } + } + +if (reset_valid (&priv->ephy_rst)) { + ret =reset_deassert (&priv->ephy_rst); +if (ret) { +dev_err (dev,"failed to deassert EPHY TX clock\n" ); +return ret; } }
@@ -839,6 +844,42 @@ static const struct eth_ops sun8i_emac_eth_ops = { .stop = sun8i_emac_eth_stop, }; +static int sun8i_get_ephy_nodes (struct emac_eth_dev *priv) +{ +int node, ret; + +/* look for mdio-mux node for internal PHY node */ + node =fdt_path_offset (gd->fdt_blob, +"/soc/ethernet at 1c30000/mdio-mux/mdio at 1/ethernet-phy at 1" ); +if (node <0 ) { +debug ("failed to get mdio-mux with internal PHY\n" ); +return node; + } + + ret =fdt_node_check_compatible (gd->fdt_blob, node, +"allwinner,sun8i-h3-mdio-internal" ); +if (ret <0 ) { +debug ("failed to find mdio-internal node\n" ); +return ret; + } + + ret =clk_get_by_index_nodev (offset_to_ofnode (node),0 , &priv->ephy_clk); +if (ret) { +dev_err (dev,"failed to get EPHY TX clock\n" ); +return ret; + } + + ret =reset_get_by_index_nodev (offset_to_ofnode (node),0 , &priv->ephy_rst); +if (ret) { +dev_err (dev,"failed to get EPHY TX reset\n" ); +return ret; + } + + priv->use_internal_phy = true; + +return 0 ; +} +static int sun8i_emac_eth_ofdata_to_platdata (struct udevice *dev) {struct sun8i_eth_pdata *sun8i_pdata =dev_get_platdata (dev);
@@ -920,12 +961,9 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev) }if (priv->variant ==H3_EMAC ) { -int parent =fdt_parent_offset (gd->fdt_blob, offset); - -if (parent >=0 && - !fdt_node_check_compatible (gd->fdt_blob, parent, -"allwinner,sun8i-h3-mdio-internal" )) - priv->use_internal_phy = true; + ret =sun8i_get_ephy_nodes (priv); +if (ret) +return ret; } priv->interface = pdata->phy_interface;
Signature · 1 line
2.18.0.321.gffc6fa0e3
PATCH v2 13/13 board: sunxi: gmac: Remove Ethernet clock and reset
In reply to Jagan TekiSince Ethernet clock and reset is now handling via CLK and RESET frameworks via driver API's remove explicit ccm writes.
--- board/sunxi/gmac.c | 8 -------- 1 file changed, 8 deletions(-)
board/sunxi/gmac.c +0 -8
@@ -12,14 +12,6 @@ void eth_init_board(void)struct sunxi_ccm_reg *const ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE ; -/* Set up clock gating */ -#ifdef CONFIG_SUNXI_GEN_SUN6I -setbits_le32 (&ccm->ahb_reset0_cfg,0x1 <<AHB_RESET_OFFSET_GMAC ); -setbits_le32 (&ccm->ahb_gate0,0x1 <<AHB_GATE_OFFSET_GMAC ); -#else -setbits_le32 (&ccm->ahb_gate1,0x1 <<AHB_GATE_OFFSET_GMAC ); -#endif -/* Set MII clock */ #ifdef CONFIG_RGMII setbits_le32(&ccm->gmac_clk_cfg, CCM_GMAC_CTRL_TX_CLK_SRC_INT_RGMII |
Signature · 1 line
2.18.0.321.gffc6fa0e3