diff options
Diffstat (limited to 'arch/arm/common')
-rw-r--r-- | arch/arm/common/Kconfig | 5 | ||||
-rw-r--r-- | arch/arm/common/Makefile | 3 | ||||
-rw-r--r-- | arch/arm/common/icst.c | 100 | ||||
-rw-r--r-- | arch/arm/common/icst307.c | 161 | ||||
-rw-r--r-- | arch/arm/common/icst525.c | 160 | ||||
-rw-r--r-- | arch/arm/common/vic.c | 107 |
6 files changed, 154 insertions, 382 deletions
diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig index cf9059091884..0a34c8186924 100644 --- a/arch/arm/common/Kconfig +++ b/arch/arm/common/Kconfig @@ -12,10 +12,7 @@ config ARM_VIC_NR The maximum number of VICs available in the system, for power management. -config ICST525 - bool - -config ICST307 +config ICST bool config PL330 diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile index df20c2650206..e6e8664a9413 100644 --- a/arch/arm/common/Makefile +++ b/arch/arm/common/Makefile @@ -4,8 +4,7 @@ obj-$(CONFIG_ARM_GIC) += gic.o obj-$(CONFIG_ARM_VIC) += vic.o -obj-$(CONFIG_ICST525) += icst525.o -obj-$(CONFIG_ICST307) += icst307.o +obj-$(CONFIG_ICST) += icst.o obj-$(CONFIG_PL330) += pl330.o obj-$(CONFIG_SA1111) += sa1111.o obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o diff --git a/arch/arm/common/icst.c b/arch/arm/common/icst.c new file mode 100644 index 000000000000..9a7f09cff300 --- /dev/null +++ b/arch/arm/common/icst.c @@ -0,0 +1,100 @@ +/* + * linux/arch/arm/common/icst307.c + * + * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Support functions for calculating clocks/divisors for the ICST307 + * clock generators. See http://www.icst.com/ for more information + * on these devices. + * + * This is an almost identical implementation to the ICST525 clock generator. + * The s2div and idx2s files are different + */ +#include <linux/module.h> +#include <linux/kernel.h> + +#include <asm/hardware/icst.h> + +/* + * Divisors for each OD setting. + */ +const unsigned char icst307_s2div[8] = { 10, 2, 8, 4, 5, 7, 3, 6 }; +const unsigned char icst525_s2div[8] = { 10, 2, 8, 4, 5, 7, 9, 6 }; +EXPORT_SYMBOL(icst307_s2div); +EXPORT_SYMBOL(icst525_s2div); + +unsigned long icst_hz(const struct icst_params *p, struct icst_vco vco) +{ + return p->ref * 2 * (vco.v + 8) / ((vco.r + 2) * p->s2div[vco.s]); +} + +EXPORT_SYMBOL(icst_hz); + +/* + * Ascending divisor S values. + */ +const unsigned char icst307_idx2s[8] = { 1, 6, 3, 4, 7, 5, 2, 0 }; +const unsigned char icst525_idx2s[8] = { 1, 3, 4, 7, 5, 2, 6, 0 }; +EXPORT_SYMBOL(icst307_idx2s); +EXPORT_SYMBOL(icst525_idx2s); + +struct icst_vco +icst_hz_to_vco(const struct icst_params *p, unsigned long freq) +{ + struct icst_vco vco = { .s = 1, .v = p->vd_max, .r = p->rd_max }; + unsigned long f; + unsigned int i = 0, rd, best = (unsigned int)-1; + + /* + * First, find the PLL output divisor such + * that the PLL output is within spec. + */ + do { + f = freq * p->s2div[p->idx2s[i]]; + + if (f > p->vco_min && f <= p->vco_max) + break; + } while (i < 8); + + if (i >= 8) + return vco; + + vco.s = p->idx2s[i]; + + /* + * Now find the closest divisor combination + * which gives a PLL output of 'f'. + */ + for (rd = p->rd_min; rd <= p->rd_max; rd++) { + unsigned long fref_div, f_pll; + unsigned int vd; + int f_diff; + + fref_div = (2 * p->ref) / rd; + + vd = (f + fref_div / 2) / fref_div; + if (vd < p->vd_min || vd > p->vd_max) + continue; + + f_pll = fref_div * vd; + f_diff = f_pll - f; + if (f_diff < 0) + f_diff = -f_diff; + + if ((unsigned)f_diff < best) { + vco.v = vd - 8; + vco.r = rd - 2; + if (f_diff == 0) + break; + best = f_diff; + } + } + + return vco; +} + +EXPORT_SYMBOL(icst_hz_to_vco); diff --git a/arch/arm/common/icst307.c b/arch/arm/common/icst307.c deleted file mode 100644 index 6d094c157540..000000000000 --- a/arch/arm/common/icst307.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * linux/arch/arm/common/icst307.c - * - * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Support functions for calculating clocks/divisors for the ICST307 - * clock generators. See http://www.icst.com/ for more information - * on these devices. - * - * This is an almost identical implementation to the ICST525 clock generator. - * The s2div and idx2s files are different - */ -#include <linux/module.h> -#include <linux/kernel.h> - -#include <asm/hardware/icst307.h> - -/* - * Divisors for each OD setting. - */ -static unsigned char s2div[8] = { 10, 2, 8, 4, 5, 7, 3, 6 }; - -unsigned long icst307_khz(const struct icst307_params *p, struct icst307_vco vco) -{ - return p->ref * 2 * (vco.v + 8) / ((vco.r + 2) * s2div[vco.s]); -} - -EXPORT_SYMBOL(icst307_khz); - -/* - * Ascending divisor S values. - */ -static unsigned char idx2s[8] = { 1, 6, 3, 4, 7, 5, 2, 0 }; - -struct icst307_vco -icst307_khz_to_vco(const struct icst307_params *p, unsigned long freq) -{ - struct icst307_vco vco = { .s = 1, .v = p->vd_max, .r = p->rd_max }; - unsigned long f; - unsigned int i = 0, rd, best = (unsigned int)-1; - - /* - * First, find the PLL output divisor such - * that the PLL output is within spec. - */ - do { - f = freq * s2div[idx2s[i]]; - - /* - * f must be between 6MHz and 200MHz (3.3 or 5V) - */ - if (f > 6000 && f <= p->vco_max) - break; - } while (i < ARRAY_SIZE(idx2s)); - - if (i >= ARRAY_SIZE(idx2s)) - return vco; - - vco.s = idx2s[i]; - - /* - * Now find the closest divisor combination - * which gives a PLL output of 'f'. - */ - for (rd = p->rd_min; rd <= p->rd_max; rd++) { - unsigned long fref_div, f_pll; - unsigned int vd; - int f_diff; - - fref_div = (2 * p->ref) / rd; - - vd = (f + fref_div / 2) / fref_div; - if (vd < p->vd_min || vd > p->vd_max) - continue; - - f_pll = fref_div * vd; - f_diff = f_pll - f; - if (f_diff < 0) - f_diff = -f_diff; - - if ((unsigned)f_diff < best) { - vco.v = vd - 8; - vco.r = rd - 2; - if (f_diff == 0) - break; - best = f_diff; - } - } - - return vco; -} - -EXPORT_SYMBOL(icst307_khz_to_vco); - -struct icst307_vco -icst307_ps_to_vco(const struct icst307_params *p, unsigned long period) -{ - struct icst307_vco vco = { .s = 1, .v = p->vd_max, .r = p->rd_max }; - unsigned long f, ps; - unsigned int i = 0, rd, best = (unsigned int)-1; - - ps = 1000000000UL / p->vco_max; - - /* - * First, find the PLL output divisor such - * that the PLL output is within spec. - */ - do { - f = period / s2div[idx2s[i]]; - - /* - * f must be between 6MHz and 200MHz (3.3 or 5V) - */ - if (f >= ps && f < 1000000000UL / 6000 + 1) - break; - } while (i < ARRAY_SIZE(idx2s)); - - if (i >= ARRAY_SIZE(idx2s)) - return vco; - - vco.s = idx2s[i]; - - ps = 500000000UL / p->ref; - - /* - * Now find the closest divisor combination - * which gives a PLL output of 'f'. - */ - for (rd = p->rd_min; rd <= p->rd_max; rd++) { - unsigned long f_in_div, f_pll; - unsigned int vd; - int f_diff; - - f_in_div = ps * rd; - - vd = (f_in_div + f / 2) / f; - if (vd < p->vd_min || vd > p->vd_max) - continue; - - f_pll = (f_in_div + vd / 2) / vd; - f_diff = f_pll - f; - if (f_diff < 0) - f_diff = -f_diff; - - if ((unsigned)f_diff < best) { - vco.v = vd - 8; - vco.r = rd - 2; - if (f_diff == 0) - break; - best = f_diff; - } - } - - return vco; -} - -EXPORT_SYMBOL(icst307_ps_to_vco); diff --git a/arch/arm/common/icst525.c b/arch/arm/common/icst525.c deleted file mode 100644 index 3d377c5bdef6..000000000000 --- a/arch/arm/common/icst525.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * linux/arch/arm/common/icst525.c - * - * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Support functions for calculating clocks/divisors for the ICST525 - * clock generators. See http://www.icst.com/ for more information - * on these devices. - */ -#include <linux/module.h> -#include <linux/kernel.h> - -#include <asm/hardware/icst525.h> - -/* - * Divisors for each OD setting. - */ -static unsigned char s2div[8] = { 10, 2, 8, 4, 5, 7, 9, 6 }; - -unsigned long icst525_khz(const struct icst525_params *p, struct icst525_vco vco) -{ - return p->ref * 2 * (vco.v + 8) / ((vco.r + 2) * s2div[vco.s]); -} - -EXPORT_SYMBOL(icst525_khz); - -/* - * Ascending divisor S values. - */ -static unsigned char idx2s[] = { 1, 3, 4, 7, 5, 2, 6, 0 }; - -struct icst525_vco -icst525_khz_to_vco(const struct icst525_params *p, unsigned long freq) -{ - struct icst525_vco vco = { .s = 1, .v = p->vd_max, .r = p->rd_max }; - unsigned long f; - unsigned int i = 0, rd, best = (unsigned int)-1; - - /* - * First, find the PLL output divisor such - * that the PLL output is within spec. - */ - do { - f = freq * s2div[idx2s[i]]; - - /* - * f must be between 10MHz and - * 320MHz (5V) or 200MHz (3V) - */ - if (f > 10000 && f <= p->vco_max) - break; - } while (i < ARRAY_SIZE(idx2s)); - - if (i >= ARRAY_SIZE(idx2s)) - return vco; - - vco.s = idx2s[i]; - - /* - * Now find the closest divisor combination - * which gives a PLL output of 'f'. - */ - for (rd = p->rd_min; rd <= p->rd_max; rd++) { - unsigned long fref_div, f_pll; - unsigned int vd; - int f_diff; - - fref_div = (2 * p->ref) / rd; - - vd = (f + fref_div / 2) / fref_div; - if (vd < p->vd_min || vd > p->vd_max) - continue; - - f_pll = fref_div * vd; - f_diff = f_pll - f; - if (f_diff < 0) - f_diff = -f_diff; - - if ((unsigned)f_diff < best) { - vco.v = vd - 8; - vco.r = rd - 2; - if (f_diff == 0) - break; - best = f_diff; - } - } - - return vco; -} - -EXPORT_SYMBOL(icst525_khz_to_vco); - -struct icst525_vco -icst525_ps_to_vco(const struct icst525_params *p, unsigned long period) -{ - struct icst525_vco vco = { .s = 1, .v = p->vd_max, .r = p->rd_max }; - unsigned long f, ps; - unsigned int i = 0, rd, best = (unsigned int)-1; - - ps = 1000000000UL / p->vco_max; - - /* - * First, find the PLL output divisor such - * that the PLL output is within spec. - */ - do { - f = period / s2div[idx2s[i]]; - - /* - * f must be between 10MHz and - * 320MHz (5V) or 200MHz (3V) - */ - if (f >= ps && f < 100000) - break; - } while (i < ARRAY_SIZE(idx2s)); - - if (i >= ARRAY_SIZE(idx2s)) - return vco; - - vco.s = idx2s[i]; - - ps = 500000000UL / p->ref; - - /* - * Now find the closest divisor combination - * which gives a PLL output of 'f'. - */ - for (rd = p->rd_min; rd <= p->rd_max; rd++) { - unsigned long f_in_div, f_pll; - unsigned int vd; - int f_diff; - - f_in_div = ps * rd; - - vd = (f_in_div + f / 2) / f; - if (vd < p->vd_min || vd > p->vd_max) - continue; - - f_pll = (f_in_div + vd / 2) / vd; - f_diff = f_pll - f; - if (f_diff < 0) - f_diff = -f_diff; - - if ((unsigned)f_diff < best) { - vco.v = vd - 8; - vco.r = rd - 2; - if (f_diff == 0) - break; - best = f_diff; - } - } - - return vco; -} - -EXPORT_SYMBOL(icst525_ps_to_vco); diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c index 1cf999ade4bc..ba65f6eedca6 100644 --- a/arch/arm/common/vic.c +++ b/arch/arm/common/vic.c @@ -266,13 +266,53 @@ static int vic_set_wake(unsigned int irq, unsigned int on) #endif /* CONFIG_PM */ static struct irq_chip vic_chip = { - .name = "VIC", - .ack = vic_ack_irq, - .mask = vic_mask_irq, - .unmask = vic_unmask_irq, - .set_wake = vic_set_wake, + .name = "VIC", + .ack = vic_ack_irq, + .mask = vic_mask_irq, + .unmask = vic_unmask_irq, + .set_wake = vic_set_wake, }; +static void __init vic_disable(void __iomem *base) +{ + writel(0, base + VIC_INT_SELECT); + writel(0, base + VIC_INT_ENABLE); + writel(~0, base + VIC_INT_ENABLE_CLEAR); + writel(0, base + VIC_IRQ_STATUS); + writel(0, base + VIC_ITCR); + writel(~0, base + VIC_INT_SOFT_CLEAR); +} + +static void __init vic_clear_interrupts(void __iomem *base) +{ + unsigned int i; + + writel(0, base + VIC_PL190_VECT_ADDR); + for (i = 0; i < 19; i++) { + unsigned int value; + + value = readl(base + VIC_PL190_VECT_ADDR); + writel(value, base + VIC_PL190_VECT_ADDR); + } +} + +static void __init vic_set_irq_sources(void __iomem *base, + unsigned int irq_start, u32 vic_sources) +{ + unsigned int i; + + for (i = 0; i < 32; i++) { + if (vic_sources & (1 << i)) { + unsigned int irq = irq_start + i; + + set_irq_chip(irq, &vic_chip); + set_irq_chip_data(irq, base); + set_irq_handler(irq, handle_level_irq); + set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + } + } +} + /* * The PL190 cell from ARM has been modified by ST to handle 64 interrupts. * The original cell has 32 interrupts, while the modified one has 64, @@ -287,13 +327,7 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start, int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0; /* Disable all interrupts initially. */ - - writel(0, base + VIC_INT_SELECT); - writel(0, base + VIC_INT_ENABLE); - writel(~0, base + VIC_INT_ENABLE_CLEAR); - writel(0, base + VIC_IRQ_STATUS); - writel(0, base + VIC_ITCR); - writel(~0, base + VIC_INT_SOFT_CLEAR); + vic_disable(base); /* * Make sure we clear all existing interrupts. The vector registers @@ -302,13 +336,8 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start, * the second base address, which is 0x20 in the page */ if (vic_2nd_block) { - writel(0, base + VIC_PL190_VECT_ADDR); - for (i = 0; i < 19; i++) { - unsigned int value; + vic_clear_interrupts(base); - value = readl(base + VIC_PL190_VECT_ADDR); - writel(value, base + VIC_PL190_VECT_ADDR); - } /* ST has 16 vectors as well, but we don't enable them by now */ for (i = 0; i < 16; i++) { void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4); @@ -318,16 +347,7 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start, writel(32, base + VIC_PL190_DEF_VECT_ADDR); } - for (i = 0; i < 32; i++) { - if (vic_sources & (1 << i)) { - unsigned int irq = irq_start + i; - - set_irq_chip(irq, &vic_chip); - set_irq_chip_data(irq, base); - set_irq_handler(irq, handle_level_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - } - } + vic_set_irq_sources(base, irq_start, vic_sources); } /** @@ -365,37 +385,14 @@ void __init vic_init(void __iomem *base, unsigned int irq_start, } /* Disable all interrupts initially. */ + vic_disable(base); - writel(0, base + VIC_INT_SELECT); - writel(0, base + VIC_INT_ENABLE); - writel(~0, base + VIC_INT_ENABLE_CLEAR); - writel(0, base + VIC_IRQ_STATUS); - writel(0, base + VIC_ITCR); - writel(~0, base + VIC_INT_SOFT_CLEAR); - - /* - * Make sure we clear all existing interrupts - */ - writel(0, base + VIC_PL190_VECT_ADDR); - for (i = 0; i < 19; i++) { - unsigned int value; - - value = readl(base + VIC_PL190_VECT_ADDR); - writel(value, base + VIC_PL190_VECT_ADDR); - } + /* Make sure we clear all existing interrupts */ + vic_clear_interrupts(base); vic_init2(base); - for (i = 0; i < 32; i++) { - if (vic_sources & (1 << i)) { - unsigned int irq = irq_start + i; - - set_irq_chip(irq, &vic_chip); - set_irq_chip_data(irq, base); - set_irq_handler(irq, handle_level_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); - } - } + vic_set_irq_sources(base, irq_start, vic_sources); vic_pm_register(base, irq_start, resume_sources); } |