Commit 62bab380 authored by Russell King's avatar Russell King

[PCMCIA] Fix up SOC PCMCIA socket timing calculations

The timing calculations used by the PXA platforms did not always take
account of the timings handed to us by PCMCIA, and where it did, it
assumed IO timings for memory windows.

We fix this, and provide a generic function which calculates the
required timings (in nanoseconds) for IO, memory and attribute
windows.  The SOC drivers only have to convert this information to
whatever format the hardware requires to achieve at least these
timing parameters.
parent 67475a9f
......@@ -115,11 +115,14 @@ static int pxa2xx_pcmcia_set_mcatt( int sock, int speed, int clock )
static int pxa2xx_pcmcia_set_mcxx(struct soc_pcmcia_socket *skt, unsigned int lclk)
{
struct soc_pcmcia_timing timing;
int sock = skt->nr;
pxa2xx_pcmcia_set_mcmem( sock, SOC_PCMCIA_5V_MEM_ACCESS, lclk );
pxa2xx_pcmcia_set_mcatt( sock, SOC_PCMCIA_ATTR_MEM_ACCESS, lclk );
pxa2xx_pcmcia_set_mcio( sock, SOC_PCMCIA_IO_ACCESS, lclk );
soc_common_pcmcia_get_timing(skt, &timing);
pxa2xx_pcmcia_set_mcmem(sock, timing.mem, lclk);
pxa2xx_pcmcia_set_mcatt(sock, timing.attr, lclk);
pxa2xx_pcmcia_set_mcio(sock, timing.io, lclk);
return 0;
}
......@@ -237,12 +240,7 @@ static void pxa2xx_pcmcia_update_mcxx(unsigned int clock)
down(&soc_sockets_lock);
list_for_each_entry(skt, &soc_sockets, node) {
pxa2xx_pcmcia_set_mcio(skt->nr, calc_speed(skt->spd_io,
MAX_IO_WIN, SOC_PCMCIA_IO_ACCESS), clock);
pxa2xx_pcmcia_set_mcmem(skt->nr, calc_speed(skt->spd_io,
MAX_IO_WIN, SOC_PCMCIA_3V_MEM_ACCESS), clock );
pxa2xx_pcmcia_set_mcatt(skt->nr, calc_speed(skt->spd_io,
MAX_IO_WIN, SOC_PCMCIA_3V_MEM_ACCESS), clock );
pxa2xx_pcmcia_set_mcxx(skt, clock);
}
up(&soc_sockets_lock);
}
......
......@@ -69,21 +69,6 @@ sa1100_pcmcia_default_mecr_timing(struct soc_pcmcia_socket *skt,
return sa1100_pcmcia_mecr_bs(cmd_time, cpu_speed);
}
static unsigned short
calc_speed(unsigned short *spds, int num, unsigned short dflt)
{
unsigned short speed = 0;
int i;
for (i = 0; i < num; i++)
if (speed < spds[i])
speed = spds[i];
if (speed == 0)
speed = dflt;
return speed;
}
/* sa1100_pcmcia_set_mecr()
* ^^^^^^^^^^^^^^^^^^^^^^^^
*
......@@ -95,19 +80,16 @@ calc_speed(unsigned short *spds, int num, unsigned short dflt)
static int
sa1100_pcmcia_set_mecr(struct soc_pcmcia_socket *skt, unsigned int cpu_clock)
{
struct soc_pcmcia_timing timing;
u32 mecr, old_mecr;
unsigned long flags;
unsigned short speed;
unsigned int bs_io, bs_mem, bs_attr;
speed = calc_speed(skt->spd_io, MAX_IO_WIN, SOC_PCMCIA_IO_ACCESS);
bs_io = skt->ops->get_timing(skt, cpu_clock, speed);
speed = calc_speed(skt->spd_mem, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS);
bs_mem = skt->ops->get_timing(skt, cpu_clock, speed);
soc_common_pcmcia_get_timing(skt, &timing);
speed = calc_speed(skt->spd_attr, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS);
bs_attr = skt->ops->get_timing(skt, cpu_clock, speed);
bs_io = skt->ops->get_timing(skt, cpu_clock, timing.io);
bs_mem = skt->ops->get_timing(skt, cpu_clock, timing.mem);
bs_attr = skt->ops->get_timing(skt, cpu_clock, timing.attr);
local_irq_save(flags);
......@@ -138,20 +120,20 @@ sa1100_pcmcia_set_timing(struct soc_pcmcia_socket *skt)
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 long mecr = MECR;
char *p = buf;
p+=sprintf(p, "I/O : %u (%u)\n",
calc_speed(skt->spd_io, MAX_IO_WIN, SOC_PCMCIA_IO_ACCESS),
soc_common_pcmcia_get_timing(skt, &timing);
p+=sprintf(p, "I/O : %u (%u)\n", timing.io,
sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, skt->nr)));
p+=sprintf(p, "attribute: %u (%u)\n",
calc_speed(skt->spd_attr, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS),
p+=sprintf(p, "attribute: %u (%u)\n", timing.attr,
sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, skt->nr)));
p+=sprintf(p, "common : %u (%u)\n",
calc_speed(skt->spd_mem, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS),
p+=sprintf(p, "common : %u (%u)\n", timing.mem,
sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, skt->nr)));
return p - buf;
......
......@@ -68,6 +68,29 @@ void soc_pcmcia_debug(struct soc_pcmcia_socket *skt, const char *func,
#define to_soc_pcmcia_socket(x) container_of(x, struct soc_pcmcia_socket, socket)
static unsigned short
calc_speed(unsigned short *spds, int num, unsigned short dflt)
{
unsigned short speed = 0;
int i;
for (i = 0; i < num; i++)
if (speed < spds[i])
speed = spds[i];
if (speed == 0)
speed = dflt;
return speed;
}
void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *skt, struct soc_pcmcia_timing *timing)
{
timing->io = calc_speed(skt->spd_io, MAX_IO_WIN, SOC_PCMCIA_IO_ACCESS);
timing->mem = calc_speed(skt->spd_mem, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS);
timing->attr = calc_speed(skt->spd_attr, MAX_WIN, SOC_PCMCIA_3V_MEM_ACCESS);
}
EXPORT_SYMBOL(soc_common_pcmcia_get_timing);
static unsigned int soc_common_pcmcia_skt_state(struct soc_pcmcia_socket *skt)
{
struct pcmcia_state state;
......
......@@ -112,10 +112,17 @@ struct pcmcia_irqs {
const char *str;
};
struct soc_pcmcia_timing {
unsigned short io;
unsigned short mem;
unsigned short attr;
};
extern int soc_pcmcia_request_irqs(struct soc_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr);
extern void soc_pcmcia_free_irqs(struct soc_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr);
extern void soc_pcmcia_disable_irqs(struct soc_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr);
extern void soc_pcmcia_enable_irqs(struct soc_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr);
extern void soc_common_pcmcia_get_timing(struct soc_pcmcia_socket *, struct soc_pcmcia_timing *);
extern struct list_head soc_pcmcia_sockets;
......
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