* [PATCH 1/5] arm: sa1100: add cpu clock
2014-10-24 10:37 [PATCH 0/5] arm: sa1100: fix sa1100 fb and pcmcia w/o cpufreq Dmitry Eremin-Solenikov
@ 2014-10-24 10:37 ` Dmitry Eremin-Solenikov
2014-10-24 10:37 ` [PATCH 2/5] arm: sa1100: add a clock alias for sa1111 pcmcia device Dmitry Eremin-Solenikov
` (4 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Dmitry Eremin-Solenikov @ 2014-10-24 10:37 UTC (permalink / raw)
To: linux-arm-kernel
Both SA1100 framebuffer and PCMCIA drivers require knowledge of cpu
frequency to correctly program timings. Currently they receive timing
information by calling cpufreq_get(0). However if cpu frequency driver
is not enabled (e.g. due to unsupported DRAM chip/board on sa1110)
cpufreq_get(0) returns 0, causing incorrect timings to be programmed.
Add cpu clock returning cpu frequency, to be used by sa11x0 fb and
pcmcia drivers.
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
arch/arm/mach-sa1100/clock.c | 41 ++++++++++++++++++++++++++++++++++-------
1 file changed, 34 insertions(+), 7 deletions(-)
diff --git a/arch/arm/mach-sa1100/clock.c b/arch/arm/mach-sa1100/clock.c
index 9fa6a99..53f750d 100644
--- a/arch/arm/mach-sa1100/clock.c
+++ b/arch/arm/mach-sa1100/clock.c
@@ -15,10 +15,12 @@
#include <linux/clkdev.h>
#include <mach/hardware.h>
+#include <mach/generic.h>
struct clkops {
void (*enable)(struct clk *);
void (*disable)(struct clk *);
+ unsigned long (*get_rate)(struct clk *);
};
struct clk {
@@ -33,13 +35,6 @@ struct clk clk_##_name = { \
static DEFINE_SPINLOCK(clocks_lock);
-/* Dummy clk routine to build generic kernel parts that may be using them */
-unsigned long clk_get_rate(struct clk *clk)
-{
- return 0;
-}
-EXPORT_SYMBOL(clk_get_rate);
-
static void clk_gpio27_enable(struct clk *clk)
{
/*
@@ -58,6 +53,19 @@ static void clk_gpio27_disable(struct clk *clk)
GAFR &= ~GPIO_32_768kHz;
}
+static void clk_cpu_enable(struct clk *clk)
+{
+}
+
+static void clk_cpu_disable(struct clk *clk)
+{
+}
+
+static unsigned long clk_cpu_get_rate(struct clk *clk)
+{
+ return sa11x0_getspeed(0) * 1000;
+}
+
int clk_enable(struct clk *clk)
{
unsigned long flags;
@@ -87,16 +95,35 @@ void clk_disable(struct clk *clk)
}
EXPORT_SYMBOL(clk_disable);
+unsigned long clk_get_rate(struct clk *clk)
+{
+ if (clk && clk->ops && clk->ops->get_rate)
+ return clk->ops->get_rate(clk);
+
+ return 0;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
const struct clkops clk_gpio27_ops = {
.enable = clk_gpio27_enable,
.disable = clk_gpio27_disable,
};
+const struct clkops clk_cpu_ops = {
+ .enable = clk_cpu_enable,
+ .disable = clk_cpu_disable,
+ .get_rate = clk_cpu_get_rate,
+};
+
static DEFINE_CLK(gpio27, &clk_gpio27_ops);
+static DEFINE_CLK(cpu, &clk_cpu_ops);
+
static struct clk_lookup sa11xx_clkregs[] = {
CLKDEV_INIT("sa1111.0", NULL, &clk_gpio27),
CLKDEV_INIT("sa1100-rtc", NULL, NULL),
+ CLKDEV_INIT("sa11x0-fb", NULL, &clk_cpu),
+ CLKDEV_INIT("sa11x0-pcmcia", NULL, &clk_cpu),
};
static int __init sa11xx_clk_init(void)
--
2.1.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/5] arm: sa1100: add a clock alias for sa1111 pcmcia device
2014-10-24 10:37 [PATCH 0/5] arm: sa1100: fix sa1100 fb and pcmcia w/o cpufreq Dmitry Eremin-Solenikov
2014-10-24 10:37 ` [PATCH 1/5] arm: sa1100: add cpu clock Dmitry Eremin-Solenikov
@ 2014-10-24 10:37 ` Dmitry Eremin-Solenikov
2014-10-24 10:37 ` [PATCH 3/5] fbdev: sa1100fb: make use of device clock Dmitry Eremin-Solenikov
` (3 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Dmitry Eremin-Solenikov @ 2014-10-24 10:37 UTC (permalink / raw)
To: linux-arm-kernel
SA-1111 uses internal MMIO space offsets as a device name, so device
name for sa1111 pcmcia is 1800 (PCMCIA is at offset 0x1800).
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
arch/arm/mach-sa1100/clock.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/mach-sa1100/clock.c b/arch/arm/mach-sa1100/clock.c
index 53f750d..03c75a8 100644
--- a/arch/arm/mach-sa1100/clock.c
+++ b/arch/arm/mach-sa1100/clock.c
@@ -124,6 +124,8 @@ static struct clk_lookup sa11xx_clkregs[] = {
CLKDEV_INIT("sa1100-rtc", NULL, NULL),
CLKDEV_INIT("sa11x0-fb", NULL, &clk_cpu),
CLKDEV_INIT("sa11x0-pcmcia", NULL, &clk_cpu),
+ /* sa1111 names devices using internal offsets, PCMCIA is at 0x1800 */
+ CLKDEV_INIT("1800", NULL, &clk_cpu),
};
static int __init sa11xx_clk_init(void)
--
2.1.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/5] fbdev: sa1100fb: make use of device clock
2014-10-24 10:37 [PATCH 0/5] arm: sa1100: fix sa1100 fb and pcmcia w/o cpufreq Dmitry Eremin-Solenikov
2014-10-24 10:37 ` [PATCH 1/5] arm: sa1100: add cpu clock Dmitry Eremin-Solenikov
2014-10-24 10:37 ` [PATCH 2/5] arm: sa1100: add a clock alias for sa1111 pcmcia device Dmitry Eremin-Solenikov
@ 2014-10-24 10:37 ` Dmitry Eremin-Solenikov
2014-10-28 10:52 ` Tomi Valkeinen
2014-10-24 10:37 ` [PATCH 4/5] pcmcia: sa1100: " Dmitry Eremin-Solenikov
` (2 subsequent siblings)
5 siblings, 1 reply; 8+ messages in thread
From: Dmitry Eremin-Solenikov @ 2014-10-24 10:37 UTC (permalink / raw)
To: linux-arm-kernel
Use per-device clock (instead of calling cpufreq_get(0), which can
return 0 if no cpu frequency driver is selected) to program timings.
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
drivers/video/fbdev/sa1100fb.c | 24 +++++++++++++++++-------
drivers/video/fbdev/sa1100fb.h | 1 +
2 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/drivers/video/fbdev/sa1100fb.c b/drivers/video/fbdev/sa1100fb.c
index 580c444e..8933840 100644
--- a/drivers/video/fbdev/sa1100fb.c
+++ b/drivers/video/fbdev/sa1100fb.c
@@ -178,6 +178,7 @@
#include <linux/dma-mapping.h>
#include <linux/mutex.h>
#include <linux/io.h>
+#include <linux/clk.h>
#include <video/sa1100fb.h>
@@ -413,9 +414,9 @@ sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
var->transp.offset);
#ifdef CONFIG_CPU_FREQ
- dev_dbg(fbi->dev, "dma period = %d ps, clock = %d kHz\n",
+ dev_dbg(fbi->dev, "dma period = %d ps, clock = %ld kHz\n",
sa1100fb_display_dma_period(var),
- cpufreq_get(smp_processor_id()));
+ clk_get_rate(fbi->clk) / 1000);
#endif
return 0;
@@ -586,9 +587,10 @@ static struct fb_ops sa1100fb_ops = {
* Calculate the PCD value from the clock rate (in picoseconds).
* We take account of the PPCR clock setting.
*/
-static inline unsigned int get_pcd(unsigned int pixclock, unsigned int cpuclock)
+static inline unsigned int get_pcd(struct sa1100fb_info *fbi,
+ unsigned int pixclock)
{
- unsigned int pcd = cpuclock / 100;
+ unsigned int pcd = clk_get_rate(fbi->clk) / 100 / 1000;
pcd *= pixclock;
pcd /= 10000000;
@@ -667,7 +669,7 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_
LCCR2_BegFrmDel(var->upper_margin) +
LCCR2_EndFrmDel(var->lower_margin);
- pcd = get_pcd(var->pixclock, cpufreq_get(0));
+ pcd = get_pcd(fbi, var->pixclock);
new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->inf->lccr3 |
(var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
(var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
@@ -1003,7 +1005,6 @@ sa1100fb_freq_transition(struct notifier_block *nb, unsigned long val,
void *data)
{
struct sa1100fb_info *fbi = TO_INF(nb, freq_transition);
- struct cpufreq_freqs *f = data;
u_int pcd;
switch (val) {
@@ -1012,7 +1013,7 @@ sa1100fb_freq_transition(struct notifier_block *nb, unsigned long val,
break;
case CPUFREQ_POSTCHANGE:
- pcd = get_pcd(fbi->fb.var.pixclock, f->new);
+ pcd = get_pcd(fbi, fbi->fb.var.pixclock);
fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
break;
@@ -1219,6 +1220,13 @@ static int sa1100fb_probe(struct platform_device *pdev)
if (!fbi)
goto failed;
+ fbi->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(fbi->clk)) {
+ ret = PTR_ERR(fbi->clk);
+ fbi->clk = NULL;
+ goto failed;
+ }
+
fbi->base = ioremap(res->start, resource_size(res));
if (!fbi->base)
goto failed;
@@ -1271,6 +1279,8 @@ static int sa1100fb_probe(struct platform_device *pdev)
failed:
if (fbi)
iounmap(fbi->base);
+ if (fbi->clk)
+ clk_put(fbi->clk);
kfree(fbi);
release_mem_region(res->start, resource_size(res));
return ret;
diff --git a/drivers/video/fbdev/sa1100fb.h b/drivers/video/fbdev/sa1100fb.h
index fc5d429..0139d13 100644
--- a/drivers/video/fbdev/sa1100fb.h
+++ b/drivers/video/fbdev/sa1100fb.h
@@ -68,6 +68,7 @@ struct sa1100fb_info {
#endif
const struct sa1100fb_mach_info *inf;
+ struct clk *clk;
};
#define TO_INF(ptr,member) container_of(ptr,struct sa1100fb_info,member)
--
2.1.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 4/5] pcmcia: sa1100: make use of device clock
2014-10-24 10:37 [PATCH 0/5] arm: sa1100: fix sa1100 fb and pcmcia w/o cpufreq Dmitry Eremin-Solenikov
` (2 preceding siblings ...)
2014-10-24 10:37 ` [PATCH 3/5] fbdev: sa1100fb: make use of device clock Dmitry Eremin-Solenikov
@ 2014-10-24 10:37 ` Dmitry Eremin-Solenikov
2014-10-24 10:37 ` [PATCH 5/5] pcmcia: sa1111: provide " Dmitry Eremin-Solenikov
2014-10-29 18:41 ` [PATCH 0/5] arm: sa1100: fix sa1100 fb and pcmcia w/o cpufreq Dmitry Eremin-Solenikov
5 siblings, 0 replies; 8+ messages in thread
From: Dmitry Eremin-Solenikov @ 2014-10-24 10:37 UTC (permalink / raw)
To: linux-arm-kernel
Use per-device clock (instead of calling cpufreq_get(0), which can
return 0 if no cpu frequency driver is selected) to program timings.
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
drivers/pcmcia/sa1100_generic.c | 1 +
drivers/pcmcia/sa11xx_base.c | 14 ++++++++++++--
2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c
index ff8a027..d2ab060 100644
--- a/drivers/pcmcia/sa1100_generic.c
+++ b/drivers/pcmcia/sa1100_generic.c
@@ -93,6 +93,7 @@ static int sa11x0_drv_pcmcia_remove(struct platform_device *dev)
for (i = 0; i < sinfo->nskt; i++)
soc_pcmcia_remove_one(&sinfo->skt[i]);
+ clk_put(sinfo->clk);
kfree(sinfo);
return 0;
}
diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c
index 54d3089..6dd94bb 100644
--- a/drivers/pcmcia/sa11xx_base.c
+++ b/drivers/pcmcia/sa11xx_base.c
@@ -135,14 +135,16 @@ sa1100_pcmcia_frequency_change(struct soc_pcmcia_socket *skt,
static int
sa1100_pcmcia_set_timing(struct soc_pcmcia_socket *skt)
{
- return sa1100_pcmcia_set_mecr(skt, cpufreq_get(0));
+ unsigned long clk = clk_get_rate(skt->clk);
+
+ return sa1100_pcmcia_set_mecr(skt, clk / 1000);
}
static int
sa1100_pcmcia_show_timing(struct soc_pcmcia_socket *skt, char *buf)
{
struct soc_pcmcia_timing timing;
- unsigned int clock = cpufreq_get(0);
+ unsigned int clock = clk_get_rate(skt->clk);
unsigned long mecr = MECR;
char *p = buf;
@@ -218,6 +220,11 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops,
struct skt_dev_info *sinfo;
struct soc_pcmcia_socket *skt;
int i, ret = 0;
+ struct clk *clk;
+
+ clk = clk_get(dev, NULL);
+ if (IS_ERR(clk))
+ return -ENODEV;
sa11xx_drv_pcmcia_ops(ops);
@@ -226,12 +233,14 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops,
return -ENOMEM;
sinfo->nskt = nr;
+ sinfo->clk = clk;
/* Initialize processor specific parameters */
for (i = 0; i < nr; i++) {
skt = &sinfo->skt[i];
skt->nr = first + i;
+ skt->clk = clk;
soc_pcmcia_init_one(skt, ops, dev);
ret = sa11xx_drv_pcmcia_add_one(skt);
@@ -242,6 +251,7 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops,
if (ret) {
while (--i >= 0)
soc_pcmcia_remove_one(&sinfo->skt[i]);
+ clk_put(clk);
kfree(sinfo);
} else {
dev_set_drvdata(dev, sinfo);
--
2.1.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 5/5] pcmcia: sa1111: provide device clock
2014-10-24 10:37 [PATCH 0/5] arm: sa1100: fix sa1100 fb and pcmcia w/o cpufreq Dmitry Eremin-Solenikov
` (3 preceding siblings ...)
2014-10-24 10:37 ` [PATCH 4/5] pcmcia: sa1100: " Dmitry Eremin-Solenikov
@ 2014-10-24 10:37 ` Dmitry Eremin-Solenikov
2014-10-29 18:41 ` [PATCH 0/5] arm: sa1100: fix sa1100 fb and pcmcia w/o cpufreq Dmitry Eremin-Solenikov
5 siblings, 0 replies; 8+ messages in thread
From: Dmitry Eremin-Solenikov @ 2014-10-24 10:37 UTC (permalink / raw)
To: linux-arm-kernel
Both pxa2xx (long ago) and sa1100 (now) make use of clock device to get
the cpu speed. Make sa1111 glue code provide clock to platform layer.
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
drivers/pcmcia/sa1111_generic.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c
index 65b02c3..c5988be 100644
--- a/drivers/pcmcia/sa1111_generic.c
+++ b/drivers/pcmcia/sa1111_generic.c
@@ -145,6 +145,9 @@ int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops,
return -ENOMEM;
s->soc.nr = ops->first + i;
+ s->soc.clk = clk_get(&dev->dev, NULL);
+ if (IS_ERR(s->soc.clk))
+ return -ENODEV;
soc_pcmcia_init_one(&s->soc, ops, &dev->dev);
s->dev = dev;
if (s->soc.nr) {
@@ -220,6 +223,7 @@ static int pcmcia_remove(struct sa1111_dev *dev)
for (; s; s = next) {
next = s->next;
soc_pcmcia_remove_one(&s->soc);
+ clk_put(s->soc.clk);
kfree(s);
}
--
2.1.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 0/5] arm: sa1100: fix sa1100 fb and pcmcia w/o cpufreq
2014-10-24 10:37 [PATCH 0/5] arm: sa1100: fix sa1100 fb and pcmcia w/o cpufreq Dmitry Eremin-Solenikov
` (4 preceding siblings ...)
2014-10-24 10:37 ` [PATCH 5/5] pcmcia: sa1111: provide " Dmitry Eremin-Solenikov
@ 2014-10-29 18:41 ` Dmitry Eremin-Solenikov
5 siblings, 0 replies; 8+ messages in thread
From: Dmitry Eremin-Solenikov @ 2014-10-29 18:41 UTC (permalink / raw)
To: linux-arm-kernel
2014-10-24 13:37 GMT+03:00 Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>:
> Hello,
>
> These patches were sitting in my queue for some time. On SA-1100
> framebuffer and PCMCIA drivers make use of cpufreq_get(0) function call
> to determine the cpu frequency. Russell's commit
> 1937f5b91833e2e8e53bcc821fc7a5fbe6ccb9b5 (ARM: fix sa1100 build) fixed
> the build issues, but broke two devices (Collie and Jornada720). For
> those two boards the cpufreq code gets compiled but is not enabled (as
> board files do not provide timing information for the CPUFREQ driver).
> Thus cpufreq_get(0) returns incorrect values and incorrect timings get
> programmed into the hardware.
>
> PXA2xx (the very similar platform) uses Clock API to determine CPU
> frequency both in framebuffer and PCMCIA drivers. These patches make
> similar changes to StrongARM drivers.
>
> These patches are required to make use of framebuffer and CF card on
> Sharp Collie (and possibly on HP Jornada 720).
Russell, what about these patches?
They are absolutely required for Collie to work properly.
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 8+ messages in thread