Commit 104f369e authored by Russell King's avatar Russell King

[PCMCIA] Add generic and per-controller power management handling.

Add per-quirk power management to aid saving/restoring controller
specific state.  Also, add proper pci state saving/restoring.
Note that Cardbus bridges have to save and restore at least 0x48
bytes of configuration space, not 0x40.

This replaces the rather muddy save state in early initialisation,
restore it on socket init stuff that we previously had.
parent 03ecd4d4
...@@ -156,39 +156,46 @@ static void ricoh_set_zv(struct yenta_socket *socket) ...@@ -156,39 +156,46 @@ static void ricoh_set_zv(struct yenta_socket *socket)
} }
} }
static int ricoh_init(struct yenta_socket *socket) static void ricoh_save_state(struct yenta_socket *socket)
{
rl_misc(socket) = config_readw(socket, RL5C4XX_MISC);
rl_ctl(socket) = config_readw(socket, RL5C4XX_16BIT_CTL);
rl_io(socket) = config_readw(socket, RL5C4XX_16BIT_IO_0);
rl_mem(socket) = config_readw(socket, RL5C4XX_16BIT_MEM_0);
rl_config(socket) = config_readw(socket, RL5C4XX_CONFIG);
}
static void ricoh_restore_state(struct yenta_socket *socket)
{ {
config_writew(socket, RL5C4XX_MISC, rl_misc(socket)); config_writew(socket, RL5C4XX_MISC, rl_misc(socket));
config_writew(socket, RL5C4XX_16BIT_CTL, rl_ctl(socket)); config_writew(socket, RL5C4XX_16BIT_CTL, rl_ctl(socket));
config_writew(socket, RL5C4XX_16BIT_IO_0, rl_io(socket)); config_writew(socket, RL5C4XX_16BIT_IO_0, rl_io(socket));
config_writew(socket, RL5C4XX_16BIT_MEM_0, rl_mem(socket)); config_writew(socket, RL5C4XX_16BIT_MEM_0, rl_mem(socket));
config_writew(socket, RL5C4XX_CONFIG, rl_config(socket)); config_writew(socket, RL5C4XX_CONFIG, rl_config(socket));
return 0;
} }
/* /*
* Magic Ricoh initialization code.. Save state at * Magic Ricoh initialization code..
* beginning, re-initialize it after suspend.
*/ */
static int ricoh_override(struct yenta_socket *socket) static int ricoh_override(struct yenta_socket *socket)
{ {
rl_misc(socket) = config_readw(socket, RL5C4XX_MISC); u16 config, ctl;
rl_ctl(socket) = config_readw(socket, RL5C4XX_16BIT_CTL);
rl_io(socket) = config_readw(socket, RL5C4XX_16BIT_IO_0); config = config_readw(socket, RL5C4XX_CONFIG);
rl_mem(socket) = config_readw(socket, RL5C4XX_16BIT_MEM_0);
rl_config(socket) = config_readw(socket, RL5C4XX_CONFIG);
/* Set the default timings, don't trust the original values */ /* Set the default timings, don't trust the original values */
rl_ctl(socket) = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING; ctl = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING;
if(socket->dev->device < PCI_DEVICE_ID_RICOH_RL5C475) { if(socket->dev->device < PCI_DEVICE_ID_RICOH_RL5C475) {
rl_ctl(socket) |= RL5C46X_16CTL_LEVEL_1 | RL5C46X_16CTL_LEVEL_2; ctl |= RL5C46X_16CTL_LEVEL_1 | RL5C46X_16CTL_LEVEL_2;
} else { } else {
rl_config(socket) |= RL5C4XX_CONFIG_PREFETCH; config |= RL5C4XX_CONFIG_PREFETCH;
} }
config_writew(socket, RL5C4XX_16BIT_CTL, ctl);
config_writew(socket, RL5C4XX_CONFIG, config);
ricoh_set_zv(socket); ricoh_set_zv(socket);
return 0; return 0;
......
...@@ -145,6 +145,26 @@ ...@@ -145,6 +145,26 @@
#define ti_diag(socket) ((socket)->private[3]) #define ti_diag(socket) ((socket)->private[3])
#define ti_irqmux(socket) ((socket)->private[4]) #define ti_irqmux(socket) ((socket)->private[4])
/*
* These are the TI specific power management handlers.
*/
static void ti_save_state(struct yenta_socket *socket)
{
ti_sysctl(socket) = config_readl(socket, TI113X_SYSTEM_CONTROL);
ti_irqmux(socket) = config_readl(socket, TI122X_IRQMUX);
ti_cardctl(socket) = config_readb(socket, TI113X_CARD_CONTROL);
ti_devctl(socket) = config_readb(socket, TI113X_DEVICE_CONTROL);
ti_diag(socket) = config_readb(socket, TI1250_DIAGNOSTIC);
}
static void ti_restore_state(struct yenta_socket *socket)
{
config_writel(socket, TI113X_SYSTEM_CONTROL, ti_sysctl(socket));
config_writel(socket, TI122X_IRQMUX, ti_irqmux(socket));
config_writeb(socket, TI113X_CARD_CONTROL, ti_cardctl(socket));
config_writeb(socket, TI113X_DEVICE_CONTROL, ti_devctl(socket));
config_writeb(socket, TI1250_DIAGNOSTIC, ti_diag(socket));
}
static int ti_intctl(struct yenta_socket *socket) static int ti_intctl(struct yenta_socket *socket)
{ {
......
...@@ -601,18 +601,6 @@ static int yenta_sock_suspend(struct pcmcia_socket *sock) ...@@ -601,18 +601,6 @@ static int yenta_sock_suspend(struct pcmcia_socket *sock)
/* Disable CSC interrupts */ /* Disable CSC interrupts */
cb_writel(socket, CB_SOCKET_MASK, 0x0); cb_writel(socket, CB_SOCKET_MASK, 0x0);
/*
* This does not work currently. The controller
* loses too much information during D3 to come up
* cleanly. We should probably fix yenta_sock_init()
* to update all the critical registers, notably
* the IO and MEM bridging region data.. That is
* something that pci_set_power_state() should
* probably know about bridges anyway.
*
pci_set_power_state(socket->dev, 3);
*/
return 0; return 0;
} }
...@@ -792,23 +780,32 @@ enum { ...@@ -792,23 +780,32 @@ enum {
struct cardbus_type cardbus_type[] = { struct cardbus_type cardbus_type[] = {
[CARDBUS_TYPE_TI] = { [CARDBUS_TYPE_TI] = {
.override = ti_override, .override = ti_override,
.save_state = ti_save_state,
.restore_state = ti_restore_state,
.sock_init = ti_init, .sock_init = ti_init,
}, },
[CARDBUS_TYPE_TI113X] = { [CARDBUS_TYPE_TI113X] = {
.override = ti113x_override, .override = ti113x_override,
.save_state = ti_save_state,
.restore_state = ti_restore_state,
.sock_init = ti113x_init, .sock_init = ti113x_init,
}, },
[CARDBUS_TYPE_TI12XX] = { [CARDBUS_TYPE_TI12XX] = {
.override = ti12xx_override, .override = ti12xx_override,
.save_state = ti_save_state,
.restore_state = ti_restore_state,
.sock_init = ti113x_init, .sock_init = ti113x_init,
}, },
[CARDBUS_TYPE_TI1250] = { [CARDBUS_TYPE_TI1250] = {
.override = ti1250_override, .override = ti1250_override,
.save_state = ti_save_state,
.restore_state = ti_restore_state,
.sock_init = ti1250_init, .sock_init = ti1250_init,
}, },
[CARDBUS_TYPE_RICOH] = { [CARDBUS_TYPE_RICOH] = {
.override = ricoh_override, .override = ricoh_override,
.sock_init = ricoh_init, .save_state = ricoh_save_state,
.restore_state = ricoh_restore_state,
}, },
}; };
...@@ -929,12 +926,41 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i ...@@ -929,12 +926,41 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i
static int yenta_dev_suspend (struct pci_dev *dev, u32 state) static int yenta_dev_suspend (struct pci_dev *dev, u32 state)
{ {
return pcmcia_socket_dev_suspend(&dev->dev, state, SUSPEND_SAVE_STATE); struct yenta_socket *socket = pci_get_drvdata(dev);
int ret;
ret = pcmcia_socket_dev_suspend(&dev->dev, state, SUSPEND_SAVE_STATE);
if (socket) {
if (socket->type && socket->type->save_state)
socket->type->save_state(socket);
/* FIXME: pci_save_state needs to have a better interface */
pci_save_state(dev, socket->saved_state);
pci_read_config_dword(dev, 16*4, &socket->saved_state[16]);
pci_read_config_dword(dev, 17*4, &socket->saved_state[17]);
pci_set_power_state(dev, 3);
}
return ret;
} }
static int yenta_dev_resume (struct pci_dev *dev) static int yenta_dev_resume (struct pci_dev *dev)
{ {
struct yenta_socket *socket = pci_get_drvdata(dev);
if (socket) {
pci_set_power_state(dev, 0);
/* FIXME: pci_restore_state needs to have a better interface */
pci_restore_state(dev, socket->saved_state);
pci_write_config_dword(dev, 16*4, socket->saved_state[16]);
pci_write_config_dword(dev, 17*4, socket->saved_state[17]);
if (socket->type && socket->type->restore_state)
socket->type->restore_state(socket);
}
return pcmcia_socket_dev_resume(&dev->dev, RESUME_RESTORE_STATE); return pcmcia_socket_dev_resume(&dev->dev, RESUME_RESTORE_STATE);
} }
......
...@@ -99,6 +99,8 @@ struct yenta_socket; ...@@ -99,6 +99,8 @@ struct yenta_socket;
struct cardbus_type { struct cardbus_type {
int (*override)(struct yenta_socket *); int (*override)(struct yenta_socket *);
void (*save_state)(struct yenta_socket *);
void (*restore_state)(struct yenta_socket *);
int (*sock_init)(struct yenta_socket *); int (*sock_init)(struct yenta_socket *);
}; };
...@@ -113,6 +115,9 @@ struct yenta_socket { ...@@ -113,6 +115,9 @@ struct yenta_socket {
/* A few words of private data for special stuff of overrides... */ /* A few words of private data for special stuff of overrides... */
unsigned int private[8]; unsigned int private[8];
/* PCI saved state */
u32 saved_state[18];
}; };
......
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