Commit 452503eb authored by Andrew Lunn's avatar Andrew Lunn Committed by Mike Turquette

ARM: Orion: Eth: Add clk/clkdev support.

The t_clk is moved from the shared part of the ethernet driver into
the per port section. Each port can have its own gated clock, which it
needs to enable/disable, as oppossed to there being one clock shared
by all ports. In practice, only kirkwood supports this at the moment.
Signed-off-by: default avatarAndrew Lunn <andrew@lunn.ch>
Tested-by: default avatarJamie Lentin <jm@lentin.co.uk>
Signed-off-by: default avatarMike Turquette <mturquette@linaro.org>
parent 4574b886
...@@ -102,8 +102,7 @@ void __init dove_ehci1_init(void) ...@@ -102,8 +102,7 @@ void __init dove_ehci1_init(void)
void __init dove_ge00_init(struct mv643xx_eth_platform_data *eth_data) void __init dove_ge00_init(struct mv643xx_eth_platform_data *eth_data)
{ {
orion_ge00_init(eth_data, orion_ge00_init(eth_data,
DOVE_GE00_PHYS_BASE, IRQ_DOVE_GE00_SUM, DOVE_GE00_PHYS_BASE, IRQ_DOVE_GE00_SUM, 0);
0, get_tclk());
} }
/***************************************************************************** /*****************************************************************************
......
...@@ -86,14 +86,14 @@ static struct clk __init *kirkwood_register_gate(const char *name, u8 bit_idx) ...@@ -86,14 +86,14 @@ static struct clk __init *kirkwood_register_gate(const char *name, u8 bit_idx)
void __init kirkwood_clk_init(void) void __init kirkwood_clk_init(void)
{ {
struct clk *runit; struct clk *runit, *ge0, *ge1;
tclk = clk_register_fixed_rate(NULL, "tclk", NULL, tclk = clk_register_fixed_rate(NULL, "tclk", NULL,
CLK_IS_ROOT, kirkwood_tclk); CLK_IS_ROOT, kirkwood_tclk);
runit = kirkwood_register_gate("runit", CGC_BIT_RUNIT); runit = kirkwood_register_gate("runit", CGC_BIT_RUNIT);
kirkwood_register_gate("ge0", CGC_BIT_GE0); ge0 = kirkwood_register_gate("ge0", CGC_BIT_GE0);
kirkwood_register_gate("ge1", CGC_BIT_GE1); ge1 = kirkwood_register_gate("ge1", CGC_BIT_GE1);
kirkwood_register_gate("sata0", CGC_BIT_SATA0); kirkwood_register_gate("sata0", CGC_BIT_SATA0);
kirkwood_register_gate("sata1", CGC_BIT_SATA1); kirkwood_register_gate("sata1", CGC_BIT_SATA1);
kirkwood_register_gate("usb0", CGC_BIT_USB0); kirkwood_register_gate("usb0", CGC_BIT_USB0);
...@@ -110,6 +110,8 @@ void __init kirkwood_clk_init(void) ...@@ -110,6 +110,8 @@ void __init kirkwood_clk_init(void)
/* clkdev entries, mapping clks to devices */ /* clkdev entries, mapping clks to devices */
orion_clkdev_add(NULL, "orion_spi.0", runit); orion_clkdev_add(NULL, "orion_spi.0", runit);
orion_clkdev_add(NULL, "orion_spi.1", runit); orion_clkdev_add(NULL, "orion_spi.1", runit);
orion_clkdev_add(NULL, MV643XX_ETH_NAME ".0", ge0);
orion_clkdev_add(NULL, MV643XX_ETH_NAME ".1", ge1);
} }
/***************************************************************************** /*****************************************************************************
...@@ -131,7 +133,7 @@ void __init kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data) ...@@ -131,7 +133,7 @@ void __init kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data)
orion_ge00_init(eth_data, orion_ge00_init(eth_data,
GE00_PHYS_BASE, IRQ_KIRKWOOD_GE00_SUM, GE00_PHYS_BASE, IRQ_KIRKWOOD_GE00_SUM,
IRQ_KIRKWOOD_GE00_ERR, kirkwood_tclk); IRQ_KIRKWOOD_GE00_ERR);
} }
...@@ -145,7 +147,7 @@ void __init kirkwood_ge01_init(struct mv643xx_eth_platform_data *eth_data) ...@@ -145,7 +147,7 @@ void __init kirkwood_ge01_init(struct mv643xx_eth_platform_data *eth_data)
orion_ge01_init(eth_data, orion_ge01_init(eth_data,
GE01_PHYS_BASE, IRQ_KIRKWOOD_GE01_SUM, GE01_PHYS_BASE, IRQ_KIRKWOOD_GE01_SUM,
IRQ_KIRKWOOD_GE01_ERR, kirkwood_tclk); IRQ_KIRKWOOD_GE01_ERR);
} }
......
...@@ -213,7 +213,7 @@ void __init mv78xx0_ge00_init(struct mv643xx_eth_platform_data *eth_data) ...@@ -213,7 +213,7 @@ void __init mv78xx0_ge00_init(struct mv643xx_eth_platform_data *eth_data)
{ {
orion_ge00_init(eth_data, orion_ge00_init(eth_data,
GE00_PHYS_BASE, IRQ_MV78XX0_GE00_SUM, GE00_PHYS_BASE, IRQ_MV78XX0_GE00_SUM,
IRQ_MV78XX0_GE_ERR, get_tclk()); IRQ_MV78XX0_GE_ERR);
} }
...@@ -224,7 +224,7 @@ void __init mv78xx0_ge01_init(struct mv643xx_eth_platform_data *eth_data) ...@@ -224,7 +224,7 @@ void __init mv78xx0_ge01_init(struct mv643xx_eth_platform_data *eth_data)
{ {
orion_ge01_init(eth_data, orion_ge01_init(eth_data,
GE01_PHYS_BASE, IRQ_MV78XX0_GE01_SUM, GE01_PHYS_BASE, IRQ_MV78XX0_GE01_SUM,
NO_IRQ, get_tclk()); NO_IRQ);
} }
...@@ -248,7 +248,7 @@ void __init mv78xx0_ge10_init(struct mv643xx_eth_platform_data *eth_data) ...@@ -248,7 +248,7 @@ void __init mv78xx0_ge10_init(struct mv643xx_eth_platform_data *eth_data)
orion_ge10_init(eth_data, orion_ge10_init(eth_data,
GE10_PHYS_BASE, IRQ_MV78XX0_GE10_SUM, GE10_PHYS_BASE, IRQ_MV78XX0_GE10_SUM,
NO_IRQ, get_tclk()); NO_IRQ);
} }
...@@ -272,7 +272,7 @@ void __init mv78xx0_ge11_init(struct mv643xx_eth_platform_data *eth_data) ...@@ -272,7 +272,7 @@ void __init mv78xx0_ge11_init(struct mv643xx_eth_platform_data *eth_data)
orion_ge11_init(eth_data, orion_ge11_init(eth_data,
GE11_PHYS_BASE, IRQ_MV78XX0_GE11_SUM, GE11_PHYS_BASE, IRQ_MV78XX0_GE11_SUM,
NO_IRQ, get_tclk()); NO_IRQ);
} }
/***************************************************************************** /*****************************************************************************
......
...@@ -109,7 +109,7 @@ void __init orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data) ...@@ -109,7 +109,7 @@ void __init orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data)
{ {
orion_ge00_init(eth_data, orion_ge00_init(eth_data,
ORION5X_ETH_PHYS_BASE, IRQ_ORION5X_ETH_SUM, ORION5X_ETH_PHYS_BASE, IRQ_ORION5X_ETH_SUM,
IRQ_ORION5X_ETH_ERR, orion5x_tclk); IRQ_ORION5X_ETH_ERR);
} }
......
...@@ -43,6 +43,10 @@ void __init orion_clkdev_init(struct clk *tclk) ...@@ -43,6 +43,10 @@ void __init orion_clkdev_init(struct clk *tclk)
{ {
orion_clkdev_add(NULL, "orion_spi.0", tclk); orion_clkdev_add(NULL, "orion_spi.0", tclk);
orion_clkdev_add(NULL, "orion_spi.1", tclk); orion_clkdev_add(NULL, "orion_spi.1", tclk);
orion_clkdev_add(NULL, MV643XX_ETH_NAME ".0", tclk);
orion_clkdev_add(NULL, MV643XX_ETH_NAME ".1", tclk);
orion_clkdev_add(NULL, MV643XX_ETH_NAME ".2", tclk);
orion_clkdev_add(NULL, MV643XX_ETH_NAME ".3", tclk);
} }
/* Fill in the resources structure and link it into the platform /* Fill in the resources structure and link it into the platform
...@@ -225,13 +229,11 @@ void __init orion_rtc_init(unsigned long mapbase, ...@@ -225,13 +229,11 @@ void __init orion_rtc_init(unsigned long mapbase,
****************************************************************************/ ****************************************************************************/
static __init void ge_complete( static __init void ge_complete(
struct mv643xx_eth_shared_platform_data *orion_ge_shared_data, struct mv643xx_eth_shared_platform_data *orion_ge_shared_data,
int tclk,
struct resource *orion_ge_resource, unsigned long irq, struct resource *orion_ge_resource, unsigned long irq,
struct platform_device *orion_ge_shared, struct platform_device *orion_ge_shared,
struct mv643xx_eth_platform_data *eth_data, struct mv643xx_eth_platform_data *eth_data,
struct platform_device *orion_ge) struct platform_device *orion_ge)
{ {
orion_ge_shared_data->t_clk = tclk;
orion_ge_resource->start = irq; orion_ge_resource->start = irq;
orion_ge_resource->end = irq; orion_ge_resource->end = irq;
eth_data->shared = orion_ge_shared; eth_data->shared = orion_ge_shared;
...@@ -282,12 +284,11 @@ static struct platform_device orion_ge00 = { ...@@ -282,12 +284,11 @@ static struct platform_device orion_ge00 = {
void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data, void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data,
unsigned long mapbase, unsigned long mapbase,
unsigned long irq, unsigned long irq,
unsigned long irq_err, unsigned long irq_err)
int tclk)
{ {
fill_resources(&orion_ge00_shared, orion_ge00_shared_resources, fill_resources(&orion_ge00_shared, orion_ge00_shared_resources,
mapbase + 0x2000, SZ_16K - 1, irq_err); mapbase + 0x2000, SZ_16K - 1, irq_err);
ge_complete(&orion_ge00_shared_data, tclk, ge_complete(&orion_ge00_shared_data,
orion_ge00_resources, irq, &orion_ge00_shared, orion_ge00_resources, irq, &orion_ge00_shared,
eth_data, &orion_ge00); eth_data, &orion_ge00);
} }
...@@ -335,12 +336,11 @@ static struct platform_device orion_ge01 = { ...@@ -335,12 +336,11 @@ static struct platform_device orion_ge01 = {
void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data, void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data,
unsigned long mapbase, unsigned long mapbase,
unsigned long irq, unsigned long irq,
unsigned long irq_err, unsigned long irq_err)
int tclk)
{ {
fill_resources(&orion_ge01_shared, orion_ge01_shared_resources, fill_resources(&orion_ge01_shared, orion_ge01_shared_resources,
mapbase + 0x2000, SZ_16K - 1, irq_err); mapbase + 0x2000, SZ_16K - 1, irq_err);
ge_complete(&orion_ge01_shared_data, tclk, ge_complete(&orion_ge01_shared_data,
orion_ge01_resources, irq, &orion_ge01_shared, orion_ge01_resources, irq, &orion_ge01_shared,
eth_data, &orion_ge01); eth_data, &orion_ge01);
} }
...@@ -388,12 +388,11 @@ static struct platform_device orion_ge10 = { ...@@ -388,12 +388,11 @@ static struct platform_device orion_ge10 = {
void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data, void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data,
unsigned long mapbase, unsigned long mapbase,
unsigned long irq, unsigned long irq,
unsigned long irq_err, unsigned long irq_err)
int tclk)
{ {
fill_resources(&orion_ge10_shared, orion_ge10_shared_resources, fill_resources(&orion_ge10_shared, orion_ge10_shared_resources,
mapbase + 0x2000, SZ_16K - 1, irq_err); mapbase + 0x2000, SZ_16K - 1, irq_err);
ge_complete(&orion_ge10_shared_data, tclk, ge_complete(&orion_ge10_shared_data,
orion_ge10_resources, irq, &orion_ge10_shared, orion_ge10_resources, irq, &orion_ge10_shared,
eth_data, &orion_ge10); eth_data, &orion_ge10);
} }
...@@ -441,12 +440,11 @@ static struct platform_device orion_ge11 = { ...@@ -441,12 +440,11 @@ static struct platform_device orion_ge11 = {
void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data, void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data,
unsigned long mapbase, unsigned long mapbase,
unsigned long irq, unsigned long irq,
unsigned long irq_err, unsigned long irq_err)
int tclk)
{ {
fill_resources(&orion_ge11_shared, orion_ge11_shared_resources, fill_resources(&orion_ge11_shared, orion_ge11_shared_resources,
mapbase + 0x2000, SZ_16K - 1, irq_err); mapbase + 0x2000, SZ_16K - 1, irq_err);
ge_complete(&orion_ge11_shared_data, tclk, ge_complete(&orion_ge11_shared_data,
orion_ge11_resources, irq, &orion_ge11_shared, orion_ge11_resources, irq, &orion_ge11_shared,
eth_data, &orion_ge11); eth_data, &orion_ge11);
} }
......
...@@ -39,29 +39,26 @@ void __init orion_rtc_init(unsigned long mapbase, ...@@ -39,29 +39,26 @@ void __init orion_rtc_init(unsigned long mapbase,
void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data, void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data,
unsigned long mapbase, unsigned long mapbase,
unsigned long irq, unsigned long irq,
unsigned long irq_err, unsigned long irq_err);
int tclk);
void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data, void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data,
unsigned long mapbase, unsigned long mapbase,
unsigned long irq, unsigned long irq,
unsigned long irq_err, unsigned long irq_err);
int tclk);
void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data, void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data,
unsigned long mapbase, unsigned long mapbase,
unsigned long irq, unsigned long irq,
unsigned long irq_err, unsigned long irq_err);
int tclk);
void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data, void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data,
unsigned long mapbase, unsigned long mapbase,
unsigned long irq, unsigned long irq,
unsigned long irq_err, unsigned long irq_err);
int tclk);
void __init orion_ge00_switch_init(struct dsa_platform_data *d, void __init orion_ge00_switch_init(struct dsa_platform_data *d,
int irq); int irq);
void __init orion_i2c_init(unsigned long mapbase, void __init orion_i2c_init(unsigned long mapbase,
unsigned long irq, unsigned long irq,
unsigned long freq_m); unsigned long freq_m);
......
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/inet_lro.h> #include <linux/inet_lro.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/clk.h>
static char mv643xx_eth_driver_name[] = "mv643xx_eth"; static char mv643xx_eth_driver_name[] = "mv643xx_eth";
static char mv643xx_eth_driver_version[] = "1.4"; static char mv643xx_eth_driver_version[] = "1.4";
...@@ -289,10 +290,10 @@ struct mv643xx_eth_shared_private { ...@@ -289,10 +290,10 @@ struct mv643xx_eth_shared_private {
/* /*
* Hardware-specific parameters. * Hardware-specific parameters.
*/ */
unsigned int t_clk;
int extended_rx_coal_limit; int extended_rx_coal_limit;
int tx_bw_control; int tx_bw_control;
int tx_csum_limit; int tx_csum_limit;
}; };
#define TX_BW_CONTROL_ABSENT 0 #define TX_BW_CONTROL_ABSENT 0
...@@ -431,6 +432,12 @@ struct mv643xx_eth_private { ...@@ -431,6 +432,12 @@ struct mv643xx_eth_private {
int tx_desc_sram_size; int tx_desc_sram_size;
int txq_count; int txq_count;
struct tx_queue txq[8]; struct tx_queue txq[8];
/*
* Hardware-specific parameters.
*/
struct clk *clk;
unsigned int t_clk;
}; };
...@@ -1010,7 +1017,7 @@ static void tx_set_rate(struct mv643xx_eth_private *mp, int rate, int burst) ...@@ -1010,7 +1017,7 @@ static void tx_set_rate(struct mv643xx_eth_private *mp, int rate, int burst)
int mtu; int mtu;
int bucket_size; int bucket_size;
token_rate = ((rate / 1000) * 64) / (mp->shared->t_clk / 1000); token_rate = ((rate / 1000) * 64) / (mp->t_clk / 1000);
if (token_rate > 1023) if (token_rate > 1023)
token_rate = 1023; token_rate = 1023;
...@@ -1042,7 +1049,7 @@ static void txq_set_rate(struct tx_queue *txq, int rate, int burst) ...@@ -1042,7 +1049,7 @@ static void txq_set_rate(struct tx_queue *txq, int rate, int burst)
int token_rate; int token_rate;
int bucket_size; int bucket_size;
token_rate = ((rate / 1000) * 64) / (mp->shared->t_clk / 1000); token_rate = ((rate / 1000) * 64) / (mp->t_clk / 1000);
if (token_rate > 1023) if (token_rate > 1023)
token_rate = 1023; token_rate = 1023;
...@@ -1309,7 +1316,7 @@ static unsigned int get_rx_coal(struct mv643xx_eth_private *mp) ...@@ -1309,7 +1316,7 @@ static unsigned int get_rx_coal(struct mv643xx_eth_private *mp)
temp = (val & 0x003fff00) >> 8; temp = (val & 0x003fff00) >> 8;
temp *= 64000000; temp *= 64000000;
do_div(temp, mp->shared->t_clk); do_div(temp, mp->t_clk);
return (unsigned int)temp; return (unsigned int)temp;
} }
...@@ -1319,7 +1326,7 @@ static void set_rx_coal(struct mv643xx_eth_private *mp, unsigned int usec) ...@@ -1319,7 +1326,7 @@ static void set_rx_coal(struct mv643xx_eth_private *mp, unsigned int usec)
u64 temp; u64 temp;
u32 val; u32 val;
temp = (u64)usec * mp->shared->t_clk; temp = (u64)usec * mp->t_clk;
temp += 31999999; temp += 31999999;
do_div(temp, 64000000); do_div(temp, 64000000);
...@@ -1345,7 +1352,7 @@ static unsigned int get_tx_coal(struct mv643xx_eth_private *mp) ...@@ -1345,7 +1352,7 @@ static unsigned int get_tx_coal(struct mv643xx_eth_private *mp)
temp = (rdlp(mp, TX_FIFO_URGENT_THRESHOLD) & 0x3fff0) >> 4; temp = (rdlp(mp, TX_FIFO_URGENT_THRESHOLD) & 0x3fff0) >> 4;
temp *= 64000000; temp *= 64000000;
do_div(temp, mp->shared->t_clk); do_div(temp, mp->t_clk);
return (unsigned int)temp; return (unsigned int)temp;
} }
...@@ -1354,7 +1361,7 @@ static void set_tx_coal(struct mv643xx_eth_private *mp, unsigned int usec) ...@@ -1354,7 +1361,7 @@ static void set_tx_coal(struct mv643xx_eth_private *mp, unsigned int usec)
{ {
u64 temp; u64 temp;
temp = (u64)usec * mp->shared->t_clk; temp = (u64)usec * mp->t_clk;
temp += 31999999; temp += 31999999;
do_div(temp, 64000000); do_div(temp, 64000000);
...@@ -2662,10 +2669,6 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev) ...@@ -2662,10 +2669,6 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
if (dram) if (dram)
mv643xx_eth_conf_mbus_windows(msp, dram); mv643xx_eth_conf_mbus_windows(msp, dram);
/*
* Detect hardware parameters.
*/
msp->t_clk = (pd != NULL && pd->t_clk != 0) ? pd->t_clk : 133000000;
msp->tx_csum_limit = (pd != NULL && pd->tx_csum_limit) ? msp->tx_csum_limit = (pd != NULL && pd->tx_csum_limit) ?
pd->tx_csum_limit : 9 * 1024; pd->tx_csum_limit : 9 * 1024;
infer_hw_params(msp); infer_hw_params(msp);
...@@ -2890,6 +2893,18 @@ static int mv643xx_eth_probe(struct platform_device *pdev) ...@@ -2890,6 +2893,18 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
mp->dev = dev; mp->dev = dev;
/*
* Get the clk rate, if there is one, otherwise use the default.
*/
mp->clk = clk_get(&pdev->dev, (pdev->id ? "1" : "0"));
if (!IS_ERR(mp->clk)) {
clk_prepare_enable(mp->clk);
mp->t_clk = clk_get_rate(mp->clk);
} else {
mp->t_clk = 133000000;
printk(KERN_WARNING "Unable to get clock");
}
set_params(mp, pd); set_params(mp, pd);
netif_set_real_num_tx_queues(dev, mp->txq_count); netif_set_real_num_tx_queues(dev, mp->txq_count);
netif_set_real_num_rx_queues(dev, mp->rxq_count); netif_set_real_num_rx_queues(dev, mp->rxq_count);
...@@ -2978,6 +2993,11 @@ static int mv643xx_eth_remove(struct platform_device *pdev) ...@@ -2978,6 +2993,11 @@ static int mv643xx_eth_remove(struct platform_device *pdev)
if (mp->phy != NULL) if (mp->phy != NULL)
phy_detach(mp->phy); phy_detach(mp->phy);
cancel_work_sync(&mp->tx_timeout_task); cancel_work_sync(&mp->tx_timeout_task);
if (!IS_ERR(mp->clk)) {
clk_disable_unprepare(mp->clk);
clk_put(mp->clk);
}
free_netdev(mp->dev); free_netdev(mp->dev);
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
struct mv643xx_eth_shared_platform_data { struct mv643xx_eth_shared_platform_data {
struct mbus_dram_target_info *dram; struct mbus_dram_target_info *dram;
struct platform_device *shared_smi; struct platform_device *shared_smi;
unsigned int t_clk;
/* /*
* Max packet size for Tx IP/Layer 4 checksum, when set to 0, default * Max packet size for Tx IP/Layer 4 checksum, when set to 0, default
* limit of 9KiB will be used. * limit of 9KiB will be used.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment