diff options
| -rw-r--r-- | Documentation/ABI/testing/sysfs-module | 12 | ||||
| -rw-r--r-- | drivers/misc/Kconfig | 12 | ||||
| -rw-r--r-- | drivers/misc/Makefile | 1 | ||||
| -rw-r--r-- | drivers/misc/pch_phub.c | 717 |
4 files changed, 742 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-module b/Documentation/ABI/testing/sysfs-module new file mode 100644 index 000000000000..cfcec3bffc0a --- /dev/null +++ b/Documentation/ABI/testing/sysfs-module | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | What: /sys/module/pch_phub/drivers/.../pch_mac | ||
| 2 | Date: August 2010 | ||
| 3 | KernelVersion: 2.6.35 | ||
| 4 | Contact: masa-korg@dsn.okisemi.com | ||
| 5 | Description: Write/read GbE MAC address. | ||
| 6 | |||
| 7 | What: /sys/module/pch_phub/drivers/.../pch_firmware | ||
| 8 | Date: August 2010 | ||
| 9 | KernelVersion: 2.6.35 | ||
| 10 | Contact: masa-korg@dsn.okisemi.com | ||
| 11 | Description: Write/read Option ROM data. | ||
| 12 | |||
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index b74331260744..6f46e27ed682 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
| @@ -390,6 +390,18 @@ config BMP085 | |||
| 390 | To compile this driver as a module, choose M here: the | 390 | To compile this driver as a module, choose M here: the |
| 391 | module will be called bmp085. | 391 | module will be called bmp085. |
| 392 | 392 | ||
| 393 | config PCH_PHUB | ||
| 394 | tristate "PCH Packet Hub of Intel Topcliff" | ||
| 395 | depends on PCI | ||
| 396 | help | ||
| 397 | This driver is for PCH(Platform controller Hub) PHUB(Packet Hub) of | ||
| 398 | Intel Topcliff which is an IOH(Input/Output Hub) for x86 embedded | ||
| 399 | processor. The Topcliff has MAC address and Option ROM data in SROM. | ||
| 400 | This driver can access MAC address and Option ROM data in SROM. | ||
| 401 | |||
| 402 | To compile this driver as a module, choose M here: the module will | ||
| 403 | be called pch_phub. | ||
| 404 | |||
| 393 | source "drivers/misc/c2port/Kconfig" | 405 | source "drivers/misc/c2port/Kconfig" |
| 394 | source "drivers/misc/eeprom/Kconfig" | 406 | source "drivers/misc/eeprom/Kconfig" |
| 395 | source "drivers/misc/cb710/Kconfig" | 407 | source "drivers/misc/cb710/Kconfig" |
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 42eab95cde2a..9f2986b4da2f 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile | |||
| @@ -35,3 +35,4 @@ obj-y += eeprom/ | |||
| 35 | obj-y += cb710/ | 35 | obj-y += cb710/ |
| 36 | obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o | 36 | obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o |
| 37 | obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o | 37 | obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o |
| 38 | obj-$(CONFIG_PCH_PHUB) += pch_phub.o | ||
diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c new file mode 100644 index 000000000000..ed56e4f91fa0 --- /dev/null +++ b/drivers/misc/pch_phub.c | |||
| @@ -0,0 +1,717 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation; version 2 of the License. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program; if not, write to the Free Software | ||
| 15 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/kernel.h> | ||
| 20 | #include <linux/types.h> | ||
| 21 | #include <linux/fs.h> | ||
| 22 | #include <linux/uaccess.h> | ||
| 23 | #include <linux/string.h> | ||
| 24 | #include <linux/pci.h> | ||
| 25 | #include <linux/io.h> | ||
| 26 | #include <linux/delay.h> | ||
| 27 | #include <linux/mutex.h> | ||
| 28 | #include <linux/if_ether.h> | ||
| 29 | #include <linux/ctype.h> | ||
| 30 | |||
| 31 | #define PHUB_STATUS 0x00 /* Status Register offset */ | ||
| 32 | #define PHUB_CONTROL 0x04 /* Control Register offset */ | ||
| 33 | #define PHUB_TIMEOUT 0x05 /* Time out value for Status Register */ | ||
| 34 | #define PCH_PHUB_ROM_WRITE_ENABLE 0x01 /* Enabling for writing ROM */ | ||
| 35 | #define PCH_PHUB_ROM_WRITE_DISABLE 0x00 /* Disabling for writing ROM */ | ||
| 36 | #define PCH_PHUB_ROM_START_ADDR 0x14 /* ROM data area start address offset */ | ||
| 37 | |||
| 38 | /* MAX number of INT_REDUCE_CONTROL registers */ | ||
| 39 | #define MAX_NUM_INT_REDUCE_CONTROL_REG 128 | ||
| 40 | #define PCI_DEVICE_ID_PCH1_PHUB 0x8801 | ||
| 41 | #define PCH_MINOR_NOS 1 | ||
| 42 | #define CLKCFG_CAN_50MHZ 0x12000000 | ||
| 43 | #define CLKCFG_CANCLK_MASK 0xFF000000 | ||
| 44 | |||
| 45 | /* SROM ACCESS Macro */ | ||
| 46 | #define PCH_WORD_ADDR_MASK (~((1 << 2) - 1)) | ||
| 47 | |||
| 48 | /* Registers address offset */ | ||
| 49 | #define PCH_PHUB_ID_REG 0x0000 | ||
| 50 | #define PCH_PHUB_QUEUE_PRI_VAL_REG 0x0004 | ||
| 51 | #define PCH_PHUB_RC_QUEUE_MAXSIZE_REG 0x0008 | ||
| 52 | #define PCH_PHUB_BRI_QUEUE_MAXSIZE_REG 0x000C | ||
| 53 | #define PCH_PHUB_COMP_RESP_TIMEOUT_REG 0x0010 | ||
| 54 | #define PCH_PHUB_BUS_SLAVE_CONTROL_REG 0x0014 | ||
| 55 | #define PCH_PHUB_DEADLOCK_AVOID_TYPE_REG 0x0018 | ||
| 56 | #define PCH_PHUB_INTPIN_REG_WPERMIT_REG0 0x0020 | ||
| 57 | #define PCH_PHUB_INTPIN_REG_WPERMIT_REG1 0x0024 | ||
| 58 | #define PCH_PHUB_INTPIN_REG_WPERMIT_REG2 0x0028 | ||
| 59 | #define PCH_PHUB_INTPIN_REG_WPERMIT_REG3 0x002C | ||
| 60 | #define PCH_PHUB_INT_REDUCE_CONTROL_REG_BASE 0x0040 | ||
| 61 | #define CLKCFG_REG_OFFSET 0x500 | ||
| 62 | |||
| 63 | #define PCH_PHUB_OROM_SIZE 15360 | ||
| 64 | |||
| 65 | /** | ||
| 66 | * struct pch_phub_reg - PHUB register structure | ||
| 67 | * @phub_id_reg: PHUB_ID register val | ||
| 68 | * @q_pri_val_reg: QUEUE_PRI_VAL register val | ||
| 69 | * @rc_q_maxsize_reg: RC_QUEUE_MAXSIZE register val | ||
| 70 | * @bri_q_maxsize_reg: BRI_QUEUE_MAXSIZE register val | ||
| 71 | * @comp_resp_timeout_reg: COMP_RESP_TIMEOUT register val | ||
| 72 | * @bus_slave_control_reg: BUS_SLAVE_CONTROL_REG register val | ||
| 73 | * @deadlock_avoid_type_reg: DEADLOCK_AVOID_TYPE register val | ||
| 74 | * @intpin_reg_wpermit_reg0: INTPIN_REG_WPERMIT register 0 val | ||
| 75 | * @intpin_reg_wpermit_reg1: INTPIN_REG_WPERMIT register 1 val | ||
| 76 | * @intpin_reg_wpermit_reg2: INTPIN_REG_WPERMIT register 2 val | ||
| 77 | * @intpin_reg_wpermit_reg3: INTPIN_REG_WPERMIT register 3 val | ||
| 78 | * @int_reduce_control_reg: INT_REDUCE_CONTROL registers val | ||
| 79 | * @clkcfg_reg: CLK CFG register val | ||
| 80 | * @pch_phub_base_address: Register base address | ||
| 81 | * @pch_phub_extrom_base_address: external rom base address | ||
| 82 | */ | ||
| 83 | struct pch_phub_reg { | ||
| 84 | u32 phub_id_reg; | ||
| 85 | u32 q_pri_val_reg; | ||
| 86 | u32 rc_q_maxsize_reg; | ||
| 87 | u32 bri_q_maxsize_reg; | ||
| 88 | u32 comp_resp_timeout_reg; | ||
| 89 | u32 bus_slave_control_reg; | ||
| 90 | u32 deadlock_avoid_type_reg; | ||
| 91 | u32 intpin_reg_wpermit_reg0; | ||
| 92 | u32 intpin_reg_wpermit_reg1; | ||
| 93 | u32 intpin_reg_wpermit_reg2; | ||
| 94 | u32 intpin_reg_wpermit_reg3; | ||
| 95 | u32 int_reduce_control_reg[MAX_NUM_INT_REDUCE_CONTROL_REG]; | ||
| 96 | u32 clkcfg_reg; | ||
| 97 | void __iomem *pch_phub_base_address; | ||
| 98 | void __iomem *pch_phub_extrom_base_address; | ||
| 99 | }; | ||
| 100 | |||
| 101 | /* SROM SPEC for MAC address assignment offset */ | ||
| 102 | static const int pch_phub_mac_offset[ETH_ALEN] = {0x3, 0x2, 0x1, 0x0, 0xb, 0xa}; | ||
| 103 | |||
| 104 | static DEFINE_MUTEX(pch_phub_mutex); | ||
| 105 | |||
| 106 | /** | ||
| 107 | * pch_phub_read_modify_write_reg() - Reading modifying and writing register | ||
| 108 | * @reg_addr_offset: Register offset address value. | ||
| 109 | * @data: Writing value. | ||
| 110 | * @mask: Mask value. | ||
| 111 | */ | ||
| 112 | static void pch_phub_read_modify_write_reg(struct pch_phub_reg *chip, | ||
| 113 | unsigned int reg_addr_offset, | ||
| 114 | unsigned int data, unsigned int mask) | ||
| 115 | { | ||
| 116 | void __iomem *reg_addr = chip->pch_phub_base_address + reg_addr_offset; | ||
| 117 | iowrite32(((ioread32(reg_addr) & ~mask)) | data, reg_addr); | ||
| 118 | } | ||
| 119 | |||
| 120 | /* pch_phub_save_reg_conf - saves register configuration */ | ||
| 121 | static void pch_phub_save_reg_conf(struct pci_dev *pdev) | ||
| 122 | { | ||
| 123 | unsigned int i; | ||
| 124 | struct pch_phub_reg *chip = pci_get_drvdata(pdev); | ||
| 125 | |||
| 126 | void __iomem *p = chip->pch_phub_base_address; | ||
| 127 | |||
| 128 | chip->phub_id_reg = ioread32(p + PCH_PHUB_ID_REG); | ||
| 129 | chip->q_pri_val_reg = ioread32(p + PCH_PHUB_QUEUE_PRI_VAL_REG); | ||
| 130 | chip->rc_q_maxsize_reg = ioread32(p + PCH_PHUB_RC_QUEUE_MAXSIZE_REG); | ||
| 131 | chip->bri_q_maxsize_reg = ioread32(p + PCH_PHUB_BRI_QUEUE_MAXSIZE_REG); | ||
| 132 | chip->comp_resp_timeout_reg = | ||
| 133 | ioread32(p + PCH_PHUB_COMP_RESP_TIMEOUT_REG); | ||
| 134 | chip->bus_slave_control_reg = | ||
| 135 | ioread32(p + PCH_PHUB_BUS_SLAVE_CONTROL_REG); | ||
| 136 | chip->deadlock_avoid_type_reg = | ||
| 137 | ioread32(p + PCH_PHUB_DEADLOCK_AVOID_TYPE_REG); | ||
| 138 | chip->intpin_reg_wpermit_reg0 = | ||
| 139 | ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG0); | ||
| 140 | chip->intpin_reg_wpermit_reg1 = | ||
| 141 | ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG1); | ||
| 142 | chip->intpin_reg_wpermit_reg2 = | ||
| 143 | ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG2); | ||
| 144 | chip->intpin_reg_wpermit_reg3 = | ||
| 145 | ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG3); | ||
| 146 | dev_dbg(&pdev->dev, "%s : " | ||
| 147 | "chip->phub_id_reg=%x, " | ||
| 148 | "chip->q_pri_val_reg=%x, " | ||
| 149 | "chip->rc_q_maxsize_reg=%x, " | ||
| 150 | "chip->bri_q_maxsize_reg=%x, " | ||
| 151 | "chip->comp_resp_timeout_reg=%x, " | ||
| 152 | "chip->bus_slave_control_reg=%x, " | ||
| 153 | "chip->deadlock_avoid_type_reg=%x, " | ||
| 154 | "chip->intpin_reg_wpermit_reg0=%x, " | ||
| 155 | "chip->intpin_reg_wpermit_reg1=%x, " | ||
| 156 | "chip->intpin_reg_wpermit_reg2=%x, " | ||
| 157 | "chip->intpin_reg_wpermit_reg3=%x\n", __func__, | ||
| 158 | chip->phub_id_reg, | ||
| 159 | chip->q_pri_val_reg, | ||
| 160 | chip->rc_q_maxsize_reg, | ||
| 161 | chip->bri_q_maxsize_reg, | ||
| 162 | chip->comp_resp_timeout_reg, | ||
| 163 | chip->bus_slave_control_reg, | ||
| 164 | chip->deadlock_avoid_type_reg, | ||
| 165 | chip->intpin_reg_wpermit_reg0, | ||
| 166 | chip->intpin_reg_wpermit_reg1, | ||
| 167 | chip->intpin_reg_wpermit_reg2, | ||
| 168 | chip->intpin_reg_wpermit_reg3); | ||
| 169 | for (i = 0; i < MAX_NUM_INT_REDUCE_CONTROL_REG; i++) { | ||
| 170 | chip->int_reduce_control_reg[i] = | ||
| 171 | ioread32(p + PCH_PHUB_INT_REDUCE_CONTROL_REG_BASE + 4 * i); | ||
| 172 | dev_dbg(&pdev->dev, "%s : " | ||
| 173 | "chip->int_reduce_control_reg[%d]=%x\n", | ||
| 174 | __func__, i, chip->int_reduce_control_reg[i]); | ||
| 175 | } | ||
| 176 | chip->clkcfg_reg = ioread32(p + CLKCFG_REG_OFFSET); | ||
| 177 | } | ||
| 178 | |||
| 179 | /* pch_phub_restore_reg_conf - restore register configuration */ | ||
| 180 | static void pch_phub_restore_reg_conf(struct pci_dev *pdev) | ||
| 181 | { | ||
| 182 | unsigned int i; | ||
| 183 | struct pch_phub_reg *chip = pci_get_drvdata(pdev); | ||
| 184 | void __iomem *p; | ||
| 185 | p = chip->pch_phub_base_address; | ||
| 186 | |||
| 187 | iowrite32(chip->phub_id_reg, p + PCH_PHUB_ID_REG); | ||
| 188 | iowrite32(chip->q_pri_val_reg, p + PCH_PHUB_QUEUE_PRI_VAL_REG); | ||
| 189 | iowrite32(chip->rc_q_maxsize_reg, p + PCH_PHUB_RC_QUEUE_MAXSIZE_REG); | ||
| 190 | iowrite32(chip->bri_q_maxsize_reg, p + PCH_PHUB_BRI_QUEUE_MAXSIZE_REG); | ||
| 191 | iowrite32(chip->comp_resp_timeout_reg, | ||
| 192 | p + PCH_PHUB_COMP_RESP_TIMEOUT_REG); | ||
| 193 | iowrite32(chip->bus_slave_control_reg, | ||
| 194 | p + PCH_PHUB_BUS_SLAVE_CONTROL_REG); | ||
| 195 | iowrite32(chip->deadlock_avoid_type_reg, | ||
| 196 | p + PCH_PHUB_DEADLOCK_AVOID_TYPE_REG); | ||
| 197 | iowrite32(chip->intpin_reg_wpermit_reg0, | ||
| 198 | p + PCH_PHUB_INTPIN_REG_WPERMIT_REG0); | ||
| 199 | iowrite32(chip->intpin_reg_wpermit_reg1, | ||
| 200 | p + PCH_PHUB_INTPIN_REG_WPERMIT_REG1); | ||
| 201 | iowrite32(chip->intpin_reg_wpermit_reg2, | ||
| 202 | p + PCH_PHUB_INTPIN_REG_WPERMIT_REG2); | ||
| 203 | iowrite32(chip->intpin_reg_wpermit_reg3, | ||
| 204 | p + PCH_PHUB_INTPIN_REG_WPERMIT_REG3); | ||
| 205 | dev_dbg(&pdev->dev, "%s : " | ||
| 206 | "chip->phub_id_reg=%x, " | ||
| 207 | "chip->q_pri_val_reg=%x, " | ||
| 208 | "chip->rc_q_maxsize_reg=%x, " | ||
| 209 | "chip->bri_q_maxsize_reg=%x, " | ||
| 210 | "chip->comp_resp_timeout_reg=%x, " | ||
| 211 | "chip->bus_slave_control_reg=%x, " | ||
| 212 | "chip->deadlock_avoid_type_reg=%x, " | ||
| 213 | "chip->intpin_reg_wpermit_reg0=%x, " | ||
| 214 | "chip->intpin_reg_wpermit_reg1=%x, " | ||
| 215 | "chip->intpin_reg_wpermit_reg2=%x, " | ||
| 216 | "chip->intpin_reg_wpermit_reg3=%x\n", __func__, | ||
| 217 | chip->phub_id_reg, | ||
| 218 | chip->q_pri_val_reg, | ||
| 219 | chip->rc_q_maxsize_reg, | ||
| 220 | chip->bri_q_maxsize_reg, | ||
| 221 | chip->comp_resp_timeout_reg, | ||
| 222 | chip->bus_slave_control_reg, | ||
| 223 | chip->deadlock_avoid_type_reg, | ||
| 224 | chip->intpin_reg_wpermit_reg0, | ||
| 225 | chip->intpin_reg_wpermit_reg1, | ||
| 226 | chip->intpin_reg_wpermit_reg2, | ||
| 227 | chip->intpin_reg_wpermit_reg3); | ||
| 228 | for (i = 0; i < MAX_NUM_INT_REDUCE_CONTROL_REG; i++) { | ||
| 229 | iowrite32(chip->int_reduce_control_reg[i], | ||
| 230 | p + PCH_PHUB_INT_REDUCE_CONTROL_REG_BASE + 4 * i); | ||
| 231 | dev_dbg(&pdev->dev, "%s : " | ||
| 232 | "chip->int_reduce_control_reg[%d]=%x\n", | ||
| 233 | __func__, i, chip->int_reduce_control_reg[i]); | ||
| 234 | } | ||
| 235 | |||
| 236 | iowrite32(chip->clkcfg_reg, p + CLKCFG_REG_OFFSET); | ||
| 237 | } | ||
| 238 | |||
| 239 | /** | ||
| 240 | * pch_phub_read_serial_rom() - Reading Serial ROM | ||
| 241 | * @offset_address: Serial ROM offset address to read. | ||
| 242 | * @data: Read buffer for specified Serial ROM value. | ||
| 243 | */ | ||
| 244 | static void pch_phub_read_serial_rom(struct pch_phub_reg *chip, | ||
| 245 | unsigned int offset_address, u8 *data) | ||
| 246 | { | ||
| 247 | void __iomem *mem_addr = chip->pch_phub_extrom_base_address + | ||
| 248 | offset_address; | ||
| 249 | |||
| 250 | *data = ioread8(mem_addr); | ||
| 251 | } | ||
| 252 | |||
| 253 | /** | ||
| 254 | * pch_phub_write_serial_rom() - Writing Serial ROM | ||
| 255 | * @offset_address: Serial ROM offset address. | ||
| 256 | * @data: Serial ROM value to write. | ||
| 257 | */ | ||
| 258 | static int pch_phub_write_serial_rom(struct pch_phub_reg *chip, | ||
| 259 | unsigned int offset_address, u8 data) | ||
| 260 | { | ||
| 261 | void __iomem *mem_addr = chip->pch_phub_extrom_base_address + | ||
| 262 | (offset_address & PCH_WORD_ADDR_MASK); | ||
| 263 | int i; | ||
| 264 | unsigned int word_data; | ||
| 265 | unsigned int pos; | ||
| 266 | unsigned int mask; | ||
| 267 | pos = (offset_address % 4) * 8; | ||
| 268 | mask = ~(0xFF << pos); | ||
| 269 | |||
| 270 | iowrite32(PCH_PHUB_ROM_WRITE_ENABLE, | ||
| 271 | chip->pch_phub_extrom_base_address + PHUB_CONTROL); | ||
| 272 | |||
| 273 | word_data = ioread32(mem_addr); | ||
| 274 | iowrite32((word_data & mask) | (u32)data << pos, mem_addr); | ||
| 275 | |||
| 276 | i = 0; | ||
| 277 | while (ioread8(chip->pch_phub_extrom_base_address + | ||
| 278 | PHUB_STATUS) != 0x00) { | ||
| 279 | msleep(1); | ||
| 280 | if (i == PHUB_TIMEOUT) | ||
| 281 | return -ETIMEDOUT; | ||
| 282 | i++; | ||
| 283 | } | ||
| 284 | |||
| 285 | iowrite32(PCH_PHUB_ROM_WRITE_DISABLE, | ||
| 286 | chip->pch_phub_extrom_base_address + PHUB_CONTROL); | ||
| 287 | |||
| 288 | return 0; | ||
| 289 | } | ||
| 290 | |||
| 291 | /** | ||
| 292 | * pch_phub_read_serial_rom_val() - Read Serial ROM value | ||
| 293 | * @offset_address: Serial ROM address offset value. | ||
| 294 | * @data: Serial ROM value to read. | ||
| 295 | */ | ||
| 296 | static void pch_phub_read_serial_rom_val(struct pch_phub_reg *chip, | ||
| 297 | unsigned int offset_address, u8 *data) | ||
| 298 | { | ||
| 299 | unsigned int mem_addr; | ||
| 300 | |||
| 301 | mem_addr = PCH_PHUB_ROM_START_ADDR + | ||
| 302 | pch_phub_mac_offset[offset_address]; | ||
| 303 | |||
| 304 | pch_phub_read_serial_rom(chip, mem_addr, data); | ||
| 305 | } | ||
| 306 | |||
| 307 | /** | ||
| 308 | * pch_phub_write_serial_rom_val() - writing Serial ROM value | ||
| 309 | * @offset_address: Serial ROM address offset value. | ||
| 310 | * @data: Serial ROM value. | ||
| 311 | */ | ||
| 312 | static int pch_phub_write_serial_rom_val(struct pch_phub_reg *chip, | ||
| 313 | unsigned int offset_address, u8 data) | ||
| 314 | { | ||
| 315 | int retval; | ||
| 316 | unsigned int mem_addr; | ||
| 317 | |||
| 318 | mem_addr = PCH_PHUB_ROM_START_ADDR + | ||
| 319 | pch_phub_mac_offset[offset_address]; | ||
| 320 | |||
| 321 | retval = pch_phub_write_serial_rom(chip, mem_addr, data); | ||
| 322 | |||
| 323 | return retval; | ||
| 324 | } | ||
| 325 | |||
| 326 | /* pch_phub_gbe_serial_rom_conf - makes Serial ROM header format configuration | ||
| 327 | * for Gigabit Ethernet MAC address | ||
| 328 | */ | ||
| 329 | static int pch_phub_gbe_serial_rom_conf(struct pch_phub_reg *chip) | ||
| 330 | { | ||
| 331 | int retval; | ||
| 332 | |||
| 333 | retval = pch_phub_write_serial_rom(chip, 0x0b, 0xbc); | ||
| 334 | retval |= pch_phub_write_serial_rom(chip, 0x0a, 0x10); | ||
| 335 | retval |= pch_phub_write_serial_rom(chip, 0x09, 0x01); | ||
| 336 | retval |= pch_phub_write_serial_rom(chip, 0x08, 0x02); | ||
| 337 | |||
| 338 | retval |= pch_phub_write_serial_rom(chip, 0x0f, 0x00); | ||
| 339 | retval |= pch_phub_write_serial_rom(chip, 0x0e, 0x00); | ||
| 340 | retval |= pch_phub_write_serial_rom(chip, 0x0d, 0x00); | ||
| 341 | retval |= pch_phub_write_serial_rom(chip, 0x0c, 0x80); | ||
| 342 | |||
| 343 | retval |= pch_phub_write_serial_rom(chip, 0x13, 0xbc); | ||
| 344 | retval |= pch_phub_write_serial_rom(chip, 0x12, 0x10); | ||
| 345 | retval |= pch_phub_write_serial_rom(chip, 0x11, 0x01); | ||
| 346 | retval |= pch_phub_write_serial_rom(chip, 0x10, 0x18); | ||
| 347 | |||
| 348 | retval |= pch_phub_write_serial_rom(chip, 0x1b, 0xbc); | ||
| 349 | retval |= pch_phub_write_serial_rom(chip, 0x1a, 0x10); | ||
| 350 | retval |= pch_phub_write_serial_rom(chip, 0x19, 0x01); | ||
| 351 | retval |= pch_phub_write_serial_rom(chip, 0x18, 0x19); | ||
| 352 | |||
| 353 | retval |= pch_phub_write_serial_rom(chip, 0x23, 0xbc); | ||
| 354 | retval |= pch_phub_write_serial_rom(chip, 0x22, 0x10); | ||
| 355 | retval |= pch_phub_write_serial_rom(chip, 0x21, 0x01); | ||
| 356 | retval |= pch_phub_write_serial_rom(chip, 0x20, 0x3a); | ||
| 357 | |||
| 358 | retval |= pch_phub_write_serial_rom(chip, 0x27, 0x01); | ||
| 359 | retval |= pch_phub_write_serial_rom(chip, 0x26, 0x00); | ||
| 360 | retval |= pch_phub_write_serial_rom(chip, 0x25, 0x00); | ||
| 361 | retval |= pch_phub_write_serial_rom(chip, 0x24, 0x00); | ||
| 362 | |||
| 363 | return retval; | ||
| 364 | } | ||
| 365 | |||
| 366 | /** | ||
| 367 | * pch_phub_read_gbe_mac_addr() - Read Gigabit Ethernet MAC address | ||
| 368 | * @offset_address: Gigabit Ethernet MAC address offset value. | ||
| 369 | * @data: Buffer of the Gigabit Ethernet MAC address value. | ||
| 370 | */ | ||
| 371 | static void pch_phub_read_gbe_mac_addr(struct pch_phub_reg *chip, u8 *data) | ||
| 372 | { | ||
| 373 | int i; | ||
| 374 | for (i = 0; i < ETH_ALEN; i++) | ||
| 375 | pch_phub_read_serial_rom_val(chip, i, &data[i]); | ||
| 376 | } | ||
| 377 | |||
| 378 | /** | ||
| 379 | * pch_phub_write_gbe_mac_addr() - Write MAC address | ||
| 380 | * @offset_address: Gigabit Ethernet MAC address offset value. | ||
| 381 | * @data: Gigabit Ethernet MAC address value. | ||
| 382 | */ | ||
| 383 | static int pch_phub_write_gbe_mac_addr(struct pch_phub_reg *chip, u8 *data) | ||
| 384 | { | ||
| 385 | int retval; | ||
| 386 | int i; | ||
| 387 | |||
| 388 | retval = pch_phub_gbe_serial_rom_conf(chip); | ||
| 389 | if (retval) | ||
| 390 | return retval; | ||
| 391 | |||
| 392 | for (i = 0; i < ETH_ALEN; i++) { | ||
| 393 | retval = pch_phub_write_serial_rom_val(chip, i, data[i]); | ||
| 394 | if (retval) | ||
| 395 | return retval; | ||
| 396 | } | ||
| 397 | |||
| 398 | return retval; | ||
| 399 | } | ||
| 400 | |||
| 401 | static ssize_t pch_phub_bin_read(struct file *filp, struct kobject *kobj, | ||
| 402 | struct bin_attribute *attr, char *buf, | ||
| 403 | loff_t off, size_t count) | ||
| 404 | { | ||
| 405 | unsigned int rom_signature; | ||
| 406 | unsigned char rom_length; | ||
| 407 | unsigned int tmp; | ||
| 408 | unsigned int addr_offset; | ||
| 409 | unsigned int orom_size; | ||
| 410 | int ret; | ||
| 411 | int err; | ||
| 412 | |||
| 413 | struct pch_phub_reg *chip = | ||
| 414 | dev_get_drvdata(container_of(kobj, struct device, kobj)); | ||
| 415 | |||
| 416 | ret = mutex_lock_interruptible(&pch_phub_mutex); | ||
| 417 | if (ret) { | ||
| 418 | err = -ERESTARTSYS; | ||
| 419 | goto return_err_nomutex; | ||
| 420 | } | ||
| 421 | |||
| 422 | /* Get Rom signature */ | ||
| 423 | pch_phub_read_serial_rom(chip, 0x80, (unsigned char *)&rom_signature); | ||
| 424 | rom_signature &= 0xff; | ||
| 425 | pch_phub_read_serial_rom(chip, 0x81, (unsigned char *)&tmp); | ||
| 426 | rom_signature |= (tmp & 0xff) << 8; | ||
| 427 | if (rom_signature == 0xAA55) { | ||
| 428 | pch_phub_read_serial_rom(chip, 0x82, &rom_length); | ||
| 429 | orom_size = rom_length * 512; | ||
| 430 | if (orom_size < off) { | ||
| 431 | addr_offset = 0; | ||
| 432 | goto return_ok; | ||
| 433 | } | ||
| 434 | if (orom_size < count) { | ||
| 435 | addr_offset = 0; | ||
| 436 | goto return_ok; | ||
| 437 | } | ||
| 438 | |||
| 439 | for (addr_offset = 0; addr_offset < count; addr_offset++) { | ||
| 440 | pch_phub_read_serial_rom(chip, 0x80 + addr_offset + off, | ||
| 441 | &buf[addr_offset]); | ||
| 442 | } | ||
| 443 | } else { | ||
| 444 | err = -ENODATA; | ||
| 445 | goto return_err; | ||
| 446 | } | ||
| 447 | return_ok: | ||
| 448 | mutex_unlock(&pch_phub_mutex); | ||
| 449 | return addr_offset; | ||
| 450 | |||
| 451 | return_err: | ||
| 452 | mutex_unlock(&pch_phub_mutex); | ||
| 453 | return_err_nomutex: | ||
| 454 | return err; | ||
| 455 | } | ||
| 456 | |||
| 457 | static ssize_t pch_phub_bin_write(struct file *filp, struct kobject *kobj, | ||
| 458 | struct bin_attribute *attr, | ||
| 459 | char *buf, loff_t off, size_t count) | ||
| 460 | { | ||
| 461 | int err; | ||
| 462 | unsigned int addr_offset; | ||
| 463 | int ret; | ||
| 464 | struct pch_phub_reg *chip = | ||
| 465 | dev_get_drvdata(container_of(kobj, struct device, kobj)); | ||
| 466 | |||
| 467 | ret = mutex_lock_interruptible(&pch_phub_mutex); | ||
| 468 | if (ret) | ||
| 469 | return -ERESTARTSYS; | ||
| 470 | |||
| 471 | if (off > PCH_PHUB_OROM_SIZE) { | ||
| 472 | addr_offset = 0; | ||
| 473 | goto return_ok; | ||
| 474 | } | ||
| 475 | if (count > PCH_PHUB_OROM_SIZE) { | ||
| 476 | addr_offset = 0; | ||
| 477 | goto return_ok; | ||
| 478 | } | ||
| 479 | |||
| 480 | for (addr_offset = 0; addr_offset < count; addr_offset++) { | ||
| 481 | if (PCH_PHUB_OROM_SIZE < off + addr_offset) | ||
| 482 | goto return_ok; | ||
| 483 | |||
| 484 | ret = pch_phub_write_serial_rom(chip, 0x80 + addr_offset + off, | ||
| 485 | buf[addr_offset]); | ||
| 486 | if (ret) { | ||
| 487 | err = ret; | ||
| 488 | goto return_err; | ||
| 489 | } | ||
| 490 | } | ||
| 491 | |||
| 492 | return_ok: | ||
| 493 | mutex_unlock(&pch_phub_mutex); | ||
| 494 | return addr_offset; | ||
| 495 | |||
| 496 | return_err: | ||
| 497 | mutex_unlock(&pch_phub_mutex); | ||
| 498 | return err; | ||
| 499 | } | ||
| 500 | |||
| 501 | static ssize_t show_pch_mac(struct device *dev, struct device_attribute *attr, | ||
| 502 | char *buf) | ||
| 503 | { | ||
| 504 | u8 mac[8]; | ||
| 505 | struct pch_phub_reg *chip = dev_get_drvdata(dev); | ||
| 506 | |||
| 507 | pch_phub_read_gbe_mac_addr(chip, mac); | ||
| 508 | |||
| 509 | return sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n", | ||
| 510 | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); | ||
| 511 | } | ||
| 512 | |||
| 513 | static ssize_t store_pch_mac(struct device *dev, struct device_attribute *attr, | ||
| 514 | const char *buf, size_t count) | ||
| 515 | { | ||
| 516 | u8 mac[6]; | ||
| 517 | struct pch_phub_reg *chip = dev_get_drvdata(dev); | ||
| 518 | |||
| 519 | if (count != 18) | ||
| 520 | return -EINVAL; | ||
| 521 | |||
| 522 | sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", | ||
| 523 | (u32 *)&mac[0], (u32 *)&mac[1], (u32 *)&mac[2], (u32 *)&mac[3], | ||
| 524 | (u32 *)&mac[4], (u32 *)&mac[5]); | ||
| 525 | |||
| 526 | pch_phub_write_gbe_mac_addr(chip, mac); | ||
| 527 | |||
| 528 | return count; | ||
| 529 | } | ||
| 530 | |||
| 531 | static DEVICE_ATTR(pch_mac, S_IRUGO | S_IWUSR, show_pch_mac, store_pch_mac); | ||
| 532 | |||
| 533 | static struct bin_attribute pch_bin_attr = { | ||
| 534 | .attr = { | ||
| 535 | .name = "pch_firmware", | ||
| 536 | .mode = S_IRUGO | S_IWUSR, | ||
| 537 | }, | ||
| 538 | .size = PCH_PHUB_OROM_SIZE + 1, | ||
| 539 | .read = pch_phub_bin_read, | ||
| 540 | .write = pch_phub_bin_write, | ||
| 541 | }; | ||
| 542 | |||
| 543 | static int __devinit pch_phub_probe(struct pci_dev *pdev, | ||
| 544 | const struct pci_device_id *id) | ||
| 545 | { | ||
| 546 | int retval; | ||
| 547 | |||
| 548 | int ret; | ||
| 549 | unsigned int rom_size; | ||
| 550 | struct pch_phub_reg *chip; | ||
| 551 | |||
| 552 | chip = kzalloc(sizeof(struct pch_phub_reg), GFP_KERNEL); | ||
| 553 | if (chip == NULL) | ||
| 554 | return -ENOMEM; | ||
| 555 | |||
| 556 | ret = pci_enable_device(pdev); | ||
| 557 | if (ret) { | ||
| 558 | dev_err(&pdev->dev, | ||
| 559 | "%s : pci_enable_device FAILED(ret=%d)", __func__, ret); | ||
| 560 | goto err_pci_enable_dev; | ||
| 561 | } | ||
| 562 | dev_dbg(&pdev->dev, "%s : pci_enable_device returns %d\n", __func__, | ||
| 563 | ret); | ||
| 564 | |||
| 565 | ret = pci_request_regions(pdev, KBUILD_MODNAME); | ||
| 566 | if (ret) { | ||
| 567 | dev_err(&pdev->dev, | ||
| 568 | "%s : pci_request_regions FAILED(ret=%d)", __func__, ret); | ||
| 569 | goto err_req_regions; | ||
| 570 | } | ||
| 571 | dev_dbg(&pdev->dev, "%s : " | ||
| 572 | "pci_request_regions returns %d\n", __func__, ret); | ||
| 573 | |||
| 574 | chip->pch_phub_base_address = pci_iomap(pdev, 1, 0); | ||
| 575 | |||
| 576 | |||
| 577 | if (chip->pch_phub_base_address == 0) { | ||
| 578 | dev_err(&pdev->dev, "%s : pci_iomap FAILED", __func__); | ||
| 579 | ret = -ENOMEM; | ||
| 580 | goto err_pci_iomap; | ||
| 581 | } | ||
| 582 | dev_dbg(&pdev->dev, "%s : pci_iomap SUCCESS and value " | ||
| 583 | "in pch_phub_base_address variable is 0x%08x\n", __func__, | ||
| 584 | (unsigned int)chip->pch_phub_base_address); | ||
| 585 | chip->pch_phub_extrom_base_address = pci_map_rom(pdev, &rom_size); | ||
| 586 | |||
| 587 | if (chip->pch_phub_extrom_base_address == 0) { | ||
| 588 | dev_err(&pdev->dev, "%s : pci_map_rom FAILED", __func__); | ||
| 589 | ret = -ENOMEM; | ||
| 590 | goto err_pci_map; | ||
| 591 | } | ||
| 592 | dev_dbg(&pdev->dev, "%s : " | ||
| 593 | "pci_map_rom SUCCESS and value in " | ||
| 594 | "pch_phub_extrom_base_address variable is 0x%08x\n", __func__, | ||
| 595 | (unsigned int)chip->pch_phub_extrom_base_address); | ||
| 596 | |||
| 597 | pci_set_drvdata(pdev, chip); | ||
| 598 | |||
| 599 | retval = sysfs_create_file(&pdev->dev.kobj, &dev_attr_pch_mac.attr); | ||
| 600 | if (retval) | ||
| 601 | goto err_sysfs_create; | ||
| 602 | |||
| 603 | retval = sysfs_create_bin_file(&pdev->dev.kobj, &pch_bin_attr); | ||
| 604 | if (retval) | ||
| 605 | goto exit_bin_attr; | ||
| 606 | |||
| 607 | pch_phub_read_modify_write_reg(chip, (unsigned int)CLKCFG_REG_OFFSET, | ||
| 608 | CLKCFG_CAN_50MHZ, CLKCFG_CANCLK_MASK); | ||
| 609 | |||
| 610 | /* set the prefech value */ | ||
| 611 | iowrite32(0x000affaa, chip->pch_phub_base_address + 0x14); | ||
| 612 | /* set the interrupt delay value */ | ||
| 613 | iowrite32(0x25, chip->pch_phub_base_address + 0x44); | ||
| 614 | |||
| 615 | return 0; | ||
| 616 | exit_bin_attr: | ||
| 617 | sysfs_remove_file(&pdev->dev.kobj, &dev_attr_pch_mac.attr); | ||
| 618 | |||
| 619 | err_sysfs_create: | ||
| 620 | pci_unmap_rom(pdev, chip->pch_phub_extrom_base_address); | ||
| 621 | err_pci_map: | ||
| 622 | pci_iounmap(pdev, chip->pch_phub_base_address); | ||
| 623 | err_pci_iomap: | ||
| 624 | pci_release_regions(pdev); | ||
| 625 | err_req_regions: | ||
| 626 | pci_disable_device(pdev); | ||
| 627 | err_pci_enable_dev: | ||
| 628 | kfree(chip); | ||
| 629 | dev_err(&pdev->dev, "%s returns %d\n", __func__, ret); | ||
| 630 | return ret; | ||
| 631 | } | ||
| 632 | |||
| 633 | static void __devexit pch_phub_remove(struct pci_dev *pdev) | ||
| 634 | { | ||
| 635 | struct pch_phub_reg *chip = pci_get_drvdata(pdev); | ||
| 636 | |||
| 637 | sysfs_remove_file(&pdev->dev.kobj, &dev_attr_pch_mac.attr); | ||
| 638 | sysfs_remove_bin_file(&pdev->dev.kobj, &pch_bin_attr); | ||
| 639 | pci_unmap_rom(pdev, chip->pch_phub_extrom_base_address); | ||
| 640 | pci_iounmap(pdev, chip->pch_phub_base_address); | ||
| 641 | pci_release_regions(pdev); | ||
| 642 | pci_disable_device(pdev); | ||
| 643 | kfree(chip); | ||
| 644 | } | ||
| 645 | |||
| 646 | #ifdef CONFIG_PM | ||
| 647 | |||
| 648 | static int pch_phub_suspend(struct pci_dev *pdev, pm_message_t state) | ||
| 649 | { | ||
| 650 | int ret; | ||
| 651 | |||
| 652 | pch_phub_save_reg_conf(pdev); | ||
| 653 | ret = pci_save_state(pdev); | ||
| 654 | if (ret) { | ||
| 655 | dev_err(&pdev->dev, | ||
| 656 | " %s -pci_save_state returns %d\n", __func__, ret); | ||
| 657 | return ret; | ||
| 658 | } | ||
| 659 | pci_enable_wake(pdev, PCI_D3hot, 0); | ||
| 660 | pci_disable_device(pdev); | ||
| 661 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | ||
| 662 | |||
| 663 | return 0; | ||
| 664 | } | ||
| 665 | |||
| 666 | static int pch_phub_resume(struct pci_dev *pdev) | ||
| 667 | { | ||
| 668 | int ret; | ||
| 669 | |||
| 670 | pci_set_power_state(pdev, PCI_D0); | ||
| 671 | pci_restore_state(pdev); | ||
| 672 | ret = pci_enable_device(pdev); | ||
| 673 | if (ret) { | ||
| 674 | dev_err(&pdev->dev, | ||
| 675 | "%s-pci_enable_device failed(ret=%d) ", __func__, ret); | ||
| 676 | return ret; | ||
| 677 | } | ||
| 678 | |||
| 679 | pci_enable_wake(pdev, PCI_D3hot, 0); | ||
| 680 | pch_phub_restore_reg_conf(pdev); | ||
| 681 | |||
| 682 | return 0; | ||
| 683 | } | ||
| 684 | #else | ||
| 685 | #define pch_phub_suspend NULL | ||
| 686 | #define pch_phub_resume NULL | ||
| 687 | #endif /* CONFIG_PM */ | ||
| 688 | |||
| 689 | static struct pci_device_id pch_phub_pcidev_id[] = { | ||
| 690 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH1_PHUB)}, | ||
| 691 | {0,} | ||
| 692 | }; | ||
| 693 | |||
| 694 | static struct pci_driver pch_phub_driver = { | ||
| 695 | .name = "pch_phub", | ||
| 696 | .id_table = pch_phub_pcidev_id, | ||
| 697 | .probe = pch_phub_probe, | ||
| 698 | .remove = __devexit_p(pch_phub_remove), | ||
| 699 | .suspend = pch_phub_suspend, | ||
| 700 | .resume = pch_phub_resume | ||
| 701 | }; | ||
| 702 | |||
| 703 | static int __init pch_phub_pci_init(void) | ||
| 704 | { | ||
| 705 | return pci_register_driver(&pch_phub_driver); | ||
| 706 | } | ||
| 707 | |||
| 708 | static void __exit pch_phub_pci_exit(void) | ||
| 709 | { | ||
| 710 | pci_unregister_driver(&pch_phub_driver); | ||
| 711 | } | ||
| 712 | |||
| 713 | module_init(pch_phub_pci_init); | ||
| 714 | module_exit(pch_phub_pci_exit); | ||
| 715 | |||
| 716 | MODULE_DESCRIPTION("PCH Packet Hub PCI Driver"); | ||
| 717 | MODULE_LICENSE("GPL"); | ||
