* (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <asm/io.h>
+#include "pm3386.h"
/*
* Read from register 'reg' of PM3386 device 'pm'.
pm3386_reg_write(port >> 1, reg, value);
}
+int pm3386_secondary_present(void)
+{
+ return pm3386_reg_read(1, 0) == 0x3386;
+}
void pm3386_reset(void)
{
- /* @@@ Implement me. */
+ u8 mac[3][6];
+ int secondary;
+
+ secondary = pm3386_secondary_present();
+
+ /* Save programmed MAC addresses. */
+ pm3386_get_mac(0, mac[0]);
+ pm3386_get_mac(1, mac[1]);
+ if (secondary)
+ pm3386_get_mac(2, mac[2]);
+
+ /* Assert analog and digital reset. */
+ pm3386_reg_write(0, 0x002, 0x0060);
+ if (secondary)
+ pm3386_reg_write(1, 0x002, 0x0060);
+ mdelay(1);
+
+ /* Deassert analog reset. */
+ pm3386_reg_write(0, 0x002, 0x0062);
+ if (secondary)
+ pm3386_reg_write(1, 0x002, 0x0062);
+ mdelay(10);
+
+ /* Deassert digital reset. */
+ pm3386_reg_write(0, 0x002, 0x0063);
+ if (secondary)
+ pm3386_reg_write(1, 0x002, 0x0063);
+ mdelay(10);
+
+ /* Restore programmed MAC addresses. */
+ pm3386_set_mac(0, mac[0]);
+ pm3386_set_mac(1, mac[1]);
+ if (secondary)
+ pm3386_set_mac(2, mac[2]);
+
+ /* Disable carrier on all ports. */
+ pm3386_set_carrier(0, 0);
+ pm3386_set_carrier(1, 0);
+ if (secondary)
+ pm3386_set_carrier(2, 0);
}
static u16 swaph(u16 x)
return ((x << 8) | (x >> 8)) & 0xffff;
}
+int pm3386_port_count(void)
+{
+ return 2 + pm3386_secondary_present();
+}
+
void pm3386_init_port(int port)
{
int pm = port >> 1;
* Soft reset the EGMAC block.
*/
pm3386_port_reg_write(port, 0x301, 0x100, 0x8000);
- udelay(10);
pm3386_port_reg_write(port, 0x301, 0x100, 0x0000);
- udelay(10);
/*
* Auto-sense autonegotiation status.
* Set autonegotiation parameters to 'no PAUSE, full duplex.'
*/
pm3386_port_reg_write(port, 0x31c, 0x100, 0x0020);
- udelay(10);
/*
* Enable and restart autonegotiation.
*/
pm3386_port_reg_write(port, 0x318, 0x100, 0x0003);
- udelay(1000);
pm3386_port_reg_write(port, 0x318, 0x100, 0x0002);
- udelay(10);
}
void pm3386_get_mac(int port, u8 *mac)
mac[5] = (temp >> 8) & 0xff;
}
+void pm3386_set_mac(int port, u8 *mac)
+{
+ pm3386_port_reg_write(port, 0x308, 0x100, (mac[1] << 8) | mac[0]);
+ pm3386_port_reg_write(port, 0x309, 0x100, (mac[3] << 8) | mac[2]);
+ pm3386_port_reg_write(port, 0x30a, 0x100, (mac[5] << 8) | mac[4]);
+}
+
static u32 pm3386_get_stat(int port, u16 base)
{
u32 value;
while (pm3386_port_reg_read(port, 0x500, 0x100) & 0x0001)
;
- memset(stats, 0, sizeof(stats));
+ memset(stats, 0, sizeof(*stats));
stats->rx_packets = pm3386_get_stat(port, 0x510);
stats->tx_packets = pm3386_get_stat(port, 0x590);
/* @@@ Add other stats. */
}
+void pm3386_set_carrier(int port, int state)
+{
+ pm3386_port_reg_write(port, 0x703, 0x10, state ? 0x1001 : 0x0000);
+}
+
int pm3386_is_link_up(int port)
{
u16 temp;
temp = pm3386_port_reg_read(port, 0x303, 0x100);
temp |= 0x1000;
pm3386_port_reg_write(port, 0x303, 0x100, temp);
-
- udelay(10);
}
void pm3386_disable_rx(int port)
temp = pm3386_port_reg_read(port, 0x303, 0x100);
temp &= 0xefff;
pm3386_port_reg_write(port, 0x303, 0x100, temp);
-
- udelay(10);
}
void pm3386_enable_tx(int port)
temp = pm3386_port_reg_read(port, 0x303, 0x100);
temp |= 0x4000;
pm3386_port_reg_write(port, 0x303, 0x100, temp);
-
- udelay(10);
}
void pm3386_disable_tx(int port)
temp = pm3386_port_reg_read(port, 0x303, 0x100);
temp &= 0xbfff;
pm3386_port_reg_write(port, 0x303, 0x100, temp);
-
- udelay(10);
}
MODULE_LICENSE("GPL");