Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / net / sfc / falcon_boards.c
similarity index 53%
rename from drivers/net/sfc/sfe4001.c
rename to drivers/net/sfc/falcon_boards.c
index 49eb91b..d31c134 100644 (file)
@@ -7,6 +7,159 @@
  * by the Free Software Foundation, incorporated herein by reference.
  */
 
+#include <linux/rtnetlink.h>
+
+#include "net_driver.h"
+#include "phy.h"
+#include "efx.h"
+#include "falcon.h"
+#include "regs.h"
+#include "io.h"
+#include "workarounds.h"
+
+/* Macros for unpacking the board revision */
+/* The revision info is in host byte order. */
+#define FALCON_BOARD_TYPE(_rev) (_rev >> 8)
+#define FALCON_BOARD_MAJOR(_rev) ((_rev >> 4) & 0xf)
+#define FALCON_BOARD_MINOR(_rev) (_rev & 0xf)
+
+/* Board types */
+#define FALCON_BOARD_SFE4001 0x01
+#define FALCON_BOARD_SFE4002 0x02
+#define FALCON_BOARD_SFN4111T 0x51
+#define FALCON_BOARD_SFN4112F 0x52
+
+/* Blink support. If the PHY has no auto-blink mode so we hang it off a timer */
+#define BLINK_INTERVAL (HZ/2)
+
+static void blink_led_timer(unsigned long context)
+{
+       struct efx_nic *efx = (struct efx_nic *)context;
+       struct efx_board *board = &efx->board_info;
+
+       board->set_id_led(efx, board->blink_state);
+       board->blink_state = !board->blink_state;
+       if (board->blink_resubmit)
+               mod_timer(&board->blink_timer, jiffies + BLINK_INTERVAL);
+}
+
+static void board_blink(struct efx_nic *efx, bool blink)
+{
+       struct efx_board *board = &efx->board_info;
+
+       /* The rtnl mutex serialises all ethtool ioctls, so
+        * nothing special needs doing here. */
+       if (blink) {
+               board->blink_resubmit = true;
+               board->blink_state = false;
+               setup_timer(&board->blink_timer, blink_led_timer,
+                           (unsigned long)efx);
+               mod_timer(&board->blink_timer, jiffies + BLINK_INTERVAL);
+       } else {
+               board->blink_resubmit = false;
+               if (board->blink_timer.function)
+                       del_timer_sync(&board->blink_timer);
+               board->init_leds(efx);
+       }
+}
+
+/*****************************************************************************
+ * Support for LM87 sensor chip used on several boards
+ */
+#define LM87_REG_ALARMS1               0x41
+#define LM87_REG_ALARMS2               0x42
+#define LM87_IN_LIMITS(nr, _min, _max)                 \
+       0x2B + (nr) * 2, _max, 0x2C + (nr) * 2, _min
+#define LM87_AIN_LIMITS(nr, _min, _max)                        \
+       0x3B + (nr), _max, 0x1A + (nr), _min
+#define LM87_TEMP_INT_LIMITS(_min, _max)               \
+       0x39, _max, 0x3A, _min
+#define LM87_TEMP_EXT1_LIMITS(_min, _max)              \
+       0x37, _max, 0x38, _min
+
+#define LM87_ALARM_TEMP_INT            0x10
+#define LM87_ALARM_TEMP_EXT1           0x20
+
+#if defined(CONFIG_SENSORS_LM87) || defined(CONFIG_SENSORS_LM87_MODULE)
+
+static int efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info,
+                        const u8 *reg_values)
+{
+       struct i2c_client *client = i2c_new_device(&efx->i2c_adap, info);
+       int rc;
+
+       if (!client)
+               return -EIO;
+
+       while (*reg_values) {
+               u8 reg = *reg_values++;
+               u8 value = *reg_values++;
+               rc = i2c_smbus_write_byte_data(client, reg, value);
+               if (rc)
+                       goto err;
+       }
+
+       efx->board_info.hwmon_client = client;
+       return 0;
+
+err:
+       i2c_unregister_device(client);
+       return rc;
+}
+
+static void efx_fini_lm87(struct efx_nic *efx)
+{
+       i2c_unregister_device(efx->board_info.hwmon_client);
+}
+
+static int efx_check_lm87(struct efx_nic *efx, unsigned mask)
+{
+       struct i2c_client *client = efx->board_info.hwmon_client;
+       s32 alarms1, alarms2;
+
+       /* If link is up then do not monitor temperature */
+       if (EFX_WORKAROUND_7884(efx) && efx->link_up)
+               return 0;
+
+       alarms1 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1);
+       alarms2 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2);
+       if (alarms1 < 0)
+               return alarms1;
+       if (alarms2 < 0)
+               return alarms2;
+       alarms1 &= mask;
+       alarms2 &= mask >> 8;
+       if (alarms1 || alarms2) {
+               EFX_ERR(efx,
+                       "LM87 detected a hardware failure (status %02x:%02x)"
+                       "%s%s\n",
+                       alarms1, alarms2,
+                       (alarms1 & LM87_ALARM_TEMP_INT) ? " INTERNAL" : "",
+                       (alarms1 & LM87_ALARM_TEMP_EXT1) ? " EXTERNAL" : "");
+               return -ERANGE;
+       }
+
+       return 0;
+}
+
+#else /* !CONFIG_SENSORS_LM87 */
+
+static inline int
+efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info,
+             const u8 *reg_values)
+{
+       return 0;
+}
+static inline void efx_fini_lm87(struct efx_nic *efx)
+{
+}
+static inline int efx_check_lm87(struct efx_nic *efx, unsigned mask)
+{
+       return 0;
+}
+
+#endif /* CONFIG_SENSORS_LM87 */
+
 /*****************************************************************************
  * Support for the SFE4001 and SFN4111T NICs.
  *
  * exclusive with the network device being open.
  */
 
-#include <linux/delay.h>
-#include <linux/rtnetlink.h>
-#include "net_driver.h"
-#include "efx.h"
-#include "phy.h"
-#include "boards.h"
-#include "falcon.h"
-#include "falcon_hwdefs.h"
-#include "falcon_io.h"
-#include "mac.h"
-#include "workarounds.h"
-
 /**************************************************************************
- *
- * I2C IO Expander device
- *
- **************************************************************************/
+ * Support for I2C IO Expander device on SFE40001
+ */
 #define        PCA9539 0x74
 
 #define        P0_IN 0x00
@@ -194,14 +333,14 @@ static int sfn4111t_reset(struct efx_nic *efx)
         * FLASH_CFG_1 strap (GPIO 3) appropriately.  Only change the
         * output enables; the output levels should always be 0 (low)
         * and we rely on external pull-ups. */
-       falcon_read(efx, &reg, GPIO_CTL_REG_KER);
-       EFX_SET_OWORD_FIELD(reg, GPIO2_OEN, true);
-       falcon_write(efx, &reg, GPIO_CTL_REG_KER);
+       efx_reado(efx, &reg, FR_AB_GPIO_CTL);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO2_OEN, true);
+       efx_writeo(efx, &reg, FR_AB_GPIO_CTL);
        msleep(1000);
-       EFX_SET_OWORD_FIELD(reg, GPIO2_OEN, false);
-       EFX_SET_OWORD_FIELD(reg, GPIO3_OEN,
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO2_OEN, false);
+       EFX_SET_OWORD_FIELD(reg, FRF_AB_GPIO3_OEN,
                            !!(efx->phy_mode & PHY_MODE_SPECIAL));
-       falcon_write(efx, &reg, GPIO_CTL_REG_KER);
+       efx_writeo(efx, &reg, FR_AB_GPIO_CTL);
        msleep(1);
 
        i2c_unlock_adapter(&efx->i2c_adap);
@@ -241,7 +380,7 @@ static ssize_t set_phy_flash_cfg(struct device *dev,
                efx->phy_mode = new_mode;
                if (new_mode & PHY_MODE_SPECIAL)
                        efx_stats_disable(efx);
-               if (efx->board_info.type == EFX_BOARD_SFE4001)
+               if (efx->board_info.type == FALCON_BOARD_SFE4001)
                        err = sfe4001_poweron(efx);
                else
                        err = sfn4111t_reset(efx);
@@ -302,7 +441,7 @@ static struct i2c_board_info sfe4001_hwmon_info = {
  * be turned on before the PHY can be used.
  * Context: Process context, rtnl lock held
  */
-int sfe4001_init(struct efx_nic *efx)
+static int sfe4001_init(struct efx_nic *efx)
 {
        int rc;
 
@@ -394,7 +533,7 @@ static struct i2c_board_info sfn4111t_r5_hwmon_info = {
        I2C_BOARD_INFO("max6646", 0x4d),
 };
 
-int sfn4111t_init(struct efx_nic *efx)
+static int sfn4111t_init(struct efx_nic *efx)
 {
        int i = 0;
        int rc;
@@ -433,3 +572,181 @@ fail_hwmon:
        i2c_unregister_device(efx->board_info.hwmon_client);
        return rc;
 }
+
+/*****************************************************************************
+ * Support for the SFE4002
+ *
+ */
+static u8 sfe4002_lm87_channel = 0x03; /* use AIN not FAN inputs */
+
+static const u8 sfe4002_lm87_regs[] = {
+       LM87_IN_LIMITS(0, 0x83, 0x91),          /* 2.5V:  1.8V +/- 5% */
+       LM87_IN_LIMITS(1, 0x51, 0x5a),          /* Vccp1: 1.2V +/- 5% */
+       LM87_IN_LIMITS(2, 0xb6, 0xca),          /* 3.3V:  3.3V +/- 5% */
+       LM87_IN_LIMITS(3, 0xb0, 0xc9),          /* 5V:    4.6-5.2V */
+       LM87_IN_LIMITS(4, 0xb0, 0xe0),          /* 12V:   11-14V */
+       LM87_IN_LIMITS(5, 0x44, 0x4b),          /* Vccp2: 1.0V +/- 5% */
+       LM87_AIN_LIMITS(0, 0xa0, 0xb2),         /* AIN1:  1.66V +/- 5% */
+       LM87_AIN_LIMITS(1, 0x91, 0xa1),         /* AIN2:  1.5V +/- 5% */
+       LM87_TEMP_INT_LIMITS(10, 60),           /* board */
+       LM87_TEMP_EXT1_LIMITS(10, 70),          /* Falcon */
+       0
+};
+
+static struct i2c_board_info sfe4002_hwmon_info = {
+       I2C_BOARD_INFO("lm87", 0x2e),
+       .platform_data  = &sfe4002_lm87_channel,
+};
+
+/****************************************************************************/
+/* LED allocations. Note that on rev A0 boards the schematic and the reality
+ * differ: red and green are swapped. Below is the fixed (A1) layout (there
+ * are only 3 A0 boards in existence, so no real reason to make this
+ * conditional).
+ */
+#define SFE4002_FAULT_LED (2)  /* Red */
+#define SFE4002_RX_LED    (0)  /* Green */
+#define SFE4002_TX_LED    (1)  /* Amber */
+
+static void sfe4002_init_leds(struct efx_nic *efx)
+{
+       /* Set the TX and RX LEDs to reflect status and activity, and the
+        * fault LED off */
+       falcon_qt202x_set_led(efx, SFE4002_TX_LED,
+                             QUAKE_LED_TXLINK | QUAKE_LED_LINK_ACTSTAT);
+       falcon_qt202x_set_led(efx, SFE4002_RX_LED,
+                             QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACTSTAT);
+       falcon_qt202x_set_led(efx, SFE4002_FAULT_LED, QUAKE_LED_OFF);
+}
+
+static void sfe4002_set_id_led(struct efx_nic *efx, bool state)
+{
+       falcon_qt202x_set_led(efx, SFE4002_FAULT_LED, state ? QUAKE_LED_ON :
+                             QUAKE_LED_OFF);
+}
+
+static int sfe4002_check_hw(struct efx_nic *efx)
+{
+       /* A0 board rev. 4002s report a temperature fault the whole time
+        * (bad sensor) so we mask it out. */
+       unsigned alarm_mask =
+               (efx->board_info.major == 0 && efx->board_info.minor == 0) ?
+               ~LM87_ALARM_TEMP_EXT1 : ~0;
+
+       return efx_check_lm87(efx, alarm_mask);
+}
+
+static int sfe4002_init(struct efx_nic *efx)
+{
+       int rc = efx_init_lm87(efx, &sfe4002_hwmon_info, sfe4002_lm87_regs);
+       if (rc)
+               return rc;
+       efx->board_info.monitor = sfe4002_check_hw;
+       efx->board_info.init_leds = sfe4002_init_leds;
+       efx->board_info.set_id_led = sfe4002_set_id_led;
+       efx->board_info.blink = board_blink;
+       efx->board_info.fini = efx_fini_lm87;
+       return 0;
+}
+
+/*****************************************************************************
+ * Support for the SFN4112F
+ *
+ */
+static u8 sfn4112f_lm87_channel = 0x03; /* use AIN not FAN inputs */
+
+static const u8 sfn4112f_lm87_regs[] = {
+       LM87_IN_LIMITS(0, 0x83, 0x91),          /* 2.5V:  1.8V +/- 5% */
+       LM87_IN_LIMITS(1, 0x51, 0x5a),          /* Vccp1: 1.2V +/- 5% */
+       LM87_IN_LIMITS(2, 0xb6, 0xca),          /* 3.3V:  3.3V +/- 5% */
+       LM87_IN_LIMITS(4, 0xb0, 0xe0),          /* 12V:   11-14V */
+       LM87_IN_LIMITS(5, 0x44, 0x4b),          /* Vccp2: 1.0V +/- 5% */
+       LM87_AIN_LIMITS(1, 0x91, 0xa1),         /* AIN2:  1.5V +/- 5% */
+       LM87_TEMP_INT_LIMITS(10, 60),           /* board */
+       LM87_TEMP_EXT1_LIMITS(10, 70),          /* Falcon */
+       0
+};
+
+static struct i2c_board_info sfn4112f_hwmon_info = {
+       I2C_BOARD_INFO("lm87", 0x2e),
+       .platform_data  = &sfn4112f_lm87_channel,
+};
+
+#define SFN4112F_ACT_LED       0
+#define SFN4112F_LINK_LED      1
+
+static void sfn4112f_init_leds(struct efx_nic *efx)
+{
+       falcon_qt202x_set_led(efx, SFN4112F_ACT_LED,
+                             QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACT);
+       falcon_qt202x_set_led(efx, SFN4112F_LINK_LED,
+                             QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT);
+}
+
+static void sfn4112f_set_id_led(struct efx_nic *efx, bool state)
+{
+       falcon_qt202x_set_led(efx, SFN4112F_LINK_LED,
+                             state ? QUAKE_LED_ON : QUAKE_LED_OFF);
+}
+
+static int sfn4112f_check_hw(struct efx_nic *efx)
+{
+       /* Mask out unused sensors */
+       return efx_check_lm87(efx, ~0x48);
+}
+
+static int sfn4112f_init(struct efx_nic *efx)
+{
+       int rc = efx_init_lm87(efx, &sfn4112f_hwmon_info, sfn4112f_lm87_regs);
+       if (rc)
+               return rc;
+       efx->board_info.monitor = sfn4112f_check_hw;
+       efx->board_info.init_leds = sfn4112f_init_leds;
+       efx->board_info.set_id_led = sfn4112f_set_id_led;
+       efx->board_info.blink = board_blink;
+       efx->board_info.fini = efx_fini_lm87;
+       return 0;
+}
+
+/* This will get expanded as board-specific details get moved out of the
+ * PHY drivers. */
+struct falcon_board_data {
+       u8 type;
+       const char *ref_model;
+       const char *gen_type;
+       int (*init) (struct efx_nic *nic);
+};
+
+
+static struct falcon_board_data board_data[] = {
+       { FALCON_BOARD_SFE4001, "SFE4001", "10GBASE-T adapter", sfe4001_init },
+       { FALCON_BOARD_SFE4002, "SFE4002", "XFP adapter", sfe4002_init },
+       { FALCON_BOARD_SFN4111T, "SFN4111T", "100/1000/10GBASE-T adapter",
+         sfn4111t_init },
+       { FALCON_BOARD_SFN4112F, "SFN4112F", "SFP+ adapter",
+         sfn4112f_init },
+};
+
+void falcon_probe_board(struct efx_nic *efx, u16 revision_info)
+{
+       struct falcon_board_data *data = NULL;
+       int i;
+
+       efx->board_info.type = FALCON_BOARD_TYPE(revision_info);
+       efx->board_info.major = FALCON_BOARD_MAJOR(revision_info);
+       efx->board_info.minor = FALCON_BOARD_MINOR(revision_info);
+
+       for (i = 0; i < ARRAY_SIZE(board_data); i++)
+               if (board_data[i].type == efx->board_info.type)
+                       data = &board_data[i];
+
+       if (data) {
+               EFX_INFO(efx, "board is %s rev %c%d\n",
+                        (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC)
+                        ? data->ref_model : data->gen_type,
+                        'A' + efx->board_info.major, efx->board_info.minor);
+               efx->board_info.init = data->init;
+       } else {
+               EFX_ERR(efx, "unknown board type %d\n", efx->board_info.type);
+       }
+}