1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd. |
4 | */ |
5 | |
6 | #include <linux/module.h> |
7 | #include <linux/kernel.h> |
8 | #include <linux/types.h> |
9 | #include <linux/fs.h> |
10 | #include <linux/uaccess.h> |
11 | #include <linux/string.h> |
12 | #include <linux/pci.h> |
13 | #include <linux/io.h> |
14 | #include <linux/delay.h> |
15 | #include <linux/mutex.h> |
16 | #include <linux/if_ether.h> |
17 | #include <linux/ctype.h> |
18 | #include <linux/dmi.h> |
19 | #include <linux/of.h> |
20 | |
21 | #define PHUB_STATUS 0x00 /* Status Register offset */ |
22 | #define PHUB_CONTROL 0x04 /* Control Register offset */ |
23 | #define PHUB_TIMEOUT 0x05 /* Time out value for Status Register */ |
24 | #define PCH_PHUB_ROM_WRITE_ENABLE 0x01 /* Enabling for writing ROM */ |
25 | #define PCH_PHUB_ROM_WRITE_DISABLE 0x00 /* Disabling for writing ROM */ |
26 | #define PCH_PHUB_MAC_START_ADDR_EG20T 0x14 /* MAC data area start address |
27 | offset */ |
28 | #define PCH_PHUB_MAC_START_ADDR_ML7223 0x20C /* MAC data area start address |
29 | offset */ |
30 | #define PCH_PHUB_ROM_START_ADDR_EG20T 0x80 /* ROM data area start address offset |
31 | (Intel EG20T PCH)*/ |
32 | #define PCH_PHUB_ROM_START_ADDR_ML7213 0x400 /* ROM data area start address |
33 | offset(LAPIS Semicon ML7213) |
34 | */ |
35 | #define PCH_PHUB_ROM_START_ADDR_ML7223 0x400 /* ROM data area start address |
36 | offset(LAPIS Semicon ML7223) |
37 | */ |
38 | |
39 | /* MAX number of INT_REDUCE_CONTROL registers */ |
40 | #define MAX_NUM_INT_REDUCE_CONTROL_REG 128 |
41 | #define PCI_DEVICE_ID_PCH1_PHUB 0x8801 |
42 | #define PCH_MINOR_NOS 1 |
43 | #define CLKCFG_CAN_50MHZ 0x12000000 |
44 | #define CLKCFG_CANCLK_MASK 0xFF000000 |
45 | #define CLKCFG_UART_MASK 0xFFFFFF |
46 | |
47 | /* CM-iTC */ |
48 | #define CLKCFG_UART_48MHZ (1 << 16) |
49 | #define CLKCFG_UART_25MHZ (2 << 16) |
50 | #define CLKCFG_BAUDDIV (2 << 20) |
51 | #define CLKCFG_PLL2VCO (8 << 9) |
52 | #define CLKCFG_UARTCLKSEL (1 << 18) |
53 | |
54 | /* Macros for ML7213 */ |
55 | #define PCI_DEVICE_ID_ROHM_ML7213_PHUB 0x801A |
56 | |
57 | /* Macros for ML7223 */ |
58 | #define PCI_DEVICE_ID_ROHM_ML7223_mPHUB 0x8012 /* for Bus-m */ |
59 | #define PCI_DEVICE_ID_ROHM_ML7223_nPHUB 0x8002 /* for Bus-n */ |
60 | |
61 | /* Macros for ML7831 */ |
62 | #define PCI_DEVICE_ID_ROHM_ML7831_PHUB 0x8801 |
63 | |
64 | /* SROM ACCESS Macro */ |
65 | #define PCH_WORD_ADDR_MASK (~((1 << 2) - 1)) |
66 | |
67 | /* Registers address offset */ |
68 | #define PCH_PHUB_ID_REG 0x0000 |
69 | #define PCH_PHUB_QUEUE_PRI_VAL_REG 0x0004 |
70 | #define PCH_PHUB_RC_QUEUE_MAXSIZE_REG 0x0008 |
71 | #define PCH_PHUB_BRI_QUEUE_MAXSIZE_REG 0x000C |
72 | #define PCH_PHUB_COMP_RESP_TIMEOUT_REG 0x0010 |
73 | #define PCH_PHUB_BUS_SLAVE_CONTROL_REG 0x0014 |
74 | #define PCH_PHUB_DEADLOCK_AVOID_TYPE_REG 0x0018 |
75 | #define PCH_PHUB_INTPIN_REG_WPERMIT_REG0 0x0020 |
76 | #define PCH_PHUB_INTPIN_REG_WPERMIT_REG1 0x0024 |
77 | #define PCH_PHUB_INTPIN_REG_WPERMIT_REG2 0x0028 |
78 | #define PCH_PHUB_INTPIN_REG_WPERMIT_REG3 0x002C |
79 | #define PCH_PHUB_INT_REDUCE_CONTROL_REG_BASE 0x0040 |
80 | #define CLKCFG_REG_OFFSET 0x500 |
81 | #define FUNCSEL_REG_OFFSET 0x508 |
82 | |
83 | #define PCH_PHUB_OROM_SIZE 15360 |
84 | |
85 | /** |
86 | * struct pch_phub_reg - PHUB register structure |
87 | * @phub_id_reg: PHUB_ID register val |
88 | * @q_pri_val_reg: QUEUE_PRI_VAL register val |
89 | * @rc_q_maxsize_reg: RC_QUEUE_MAXSIZE register val |
90 | * @bri_q_maxsize_reg: BRI_QUEUE_MAXSIZE register val |
91 | * @comp_resp_timeout_reg: COMP_RESP_TIMEOUT register val |
92 | * @bus_slave_control_reg: BUS_SLAVE_CONTROL_REG register val |
93 | * @deadlock_avoid_type_reg: DEADLOCK_AVOID_TYPE register val |
94 | * @intpin_reg_wpermit_reg0: INTPIN_REG_WPERMIT register 0 val |
95 | * @intpin_reg_wpermit_reg1: INTPIN_REG_WPERMIT register 1 val |
96 | * @intpin_reg_wpermit_reg2: INTPIN_REG_WPERMIT register 2 val |
97 | * @intpin_reg_wpermit_reg3: INTPIN_REG_WPERMIT register 3 val |
98 | * @int_reduce_control_reg: INT_REDUCE_CONTROL registers val |
99 | * @clkcfg_reg: CLK CFG register val |
100 | * @funcsel_reg: Function select register value |
101 | * @pch_phub_base_address: Register base address |
102 | * @pch_phub_extrom_base_address: external rom base address |
103 | * @pch_mac_start_address: MAC address area start address |
104 | * @pch_opt_rom_start_address: Option ROM start address |
105 | * @ioh_type: Save IOH type |
106 | * @pdev: pointer to pci device struct |
107 | */ |
108 | struct pch_phub_reg { |
109 | u32 phub_id_reg; |
110 | u32 q_pri_val_reg; |
111 | u32 rc_q_maxsize_reg; |
112 | u32 bri_q_maxsize_reg; |
113 | u32 comp_resp_timeout_reg; |
114 | u32 bus_slave_control_reg; |
115 | u32 deadlock_avoid_type_reg; |
116 | u32 intpin_reg_wpermit_reg0; |
117 | u32 intpin_reg_wpermit_reg1; |
118 | u32 intpin_reg_wpermit_reg2; |
119 | u32 intpin_reg_wpermit_reg3; |
120 | u32 int_reduce_control_reg[MAX_NUM_INT_REDUCE_CONTROL_REG]; |
121 | u32 clkcfg_reg; |
122 | u32 funcsel_reg; |
123 | void __iomem *pch_phub_base_address; |
124 | void __iomem *pch_phub_extrom_base_address; |
125 | u32 pch_mac_start_address; |
126 | u32 pch_opt_rom_start_address; |
127 | int ioh_type; |
128 | struct pci_dev *pdev; |
129 | }; |
130 | |
131 | /* SROM SPEC for MAC address assignment offset */ |
132 | static const int pch_phub_mac_offset[ETH_ALEN] = {0x3, 0x2, 0x1, 0x0, 0xb, 0xa}; |
133 | |
134 | static DEFINE_MUTEX(pch_phub_mutex); |
135 | |
136 | /** |
137 | * pch_phub_read_modify_write_reg() - Reading modifying and writing register |
138 | * @chip: Pointer to the PHUB register structure |
139 | * @reg_addr_offset: Register offset address value. |
140 | * @data: Writing value. |
141 | * @mask: Mask value. |
142 | */ |
143 | static void pch_phub_read_modify_write_reg(struct pch_phub_reg *chip, |
144 | unsigned int reg_addr_offset, |
145 | unsigned int data, unsigned int mask) |
146 | { |
147 | void __iomem *reg_addr = chip->pch_phub_base_address + reg_addr_offset; |
148 | iowrite32(((ioread32(reg_addr) & ~mask)) | data, reg_addr); |
149 | } |
150 | |
151 | /* pch_phub_save_reg_conf - saves register configuration */ |
152 | static void __maybe_unused pch_phub_save_reg_conf(struct pci_dev *pdev) |
153 | { |
154 | unsigned int i; |
155 | struct pch_phub_reg *chip = pci_get_drvdata(pdev); |
156 | |
157 | void __iomem *p = chip->pch_phub_base_address; |
158 | |
159 | chip->phub_id_reg = ioread32(p + PCH_PHUB_ID_REG); |
160 | chip->q_pri_val_reg = ioread32(p + PCH_PHUB_QUEUE_PRI_VAL_REG); |
161 | chip->rc_q_maxsize_reg = ioread32(p + PCH_PHUB_RC_QUEUE_MAXSIZE_REG); |
162 | chip->bri_q_maxsize_reg = ioread32(p + PCH_PHUB_BRI_QUEUE_MAXSIZE_REG); |
163 | chip->comp_resp_timeout_reg = |
164 | ioread32(p + PCH_PHUB_COMP_RESP_TIMEOUT_REG); |
165 | chip->bus_slave_control_reg = |
166 | ioread32(p + PCH_PHUB_BUS_SLAVE_CONTROL_REG); |
167 | chip->deadlock_avoid_type_reg = |
168 | ioread32(p + PCH_PHUB_DEADLOCK_AVOID_TYPE_REG); |
169 | chip->intpin_reg_wpermit_reg0 = |
170 | ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG0); |
171 | chip->intpin_reg_wpermit_reg1 = |
172 | ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG1); |
173 | chip->intpin_reg_wpermit_reg2 = |
174 | ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG2); |
175 | chip->intpin_reg_wpermit_reg3 = |
176 | ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG3); |
177 | dev_dbg(&pdev->dev, "%s : " |
178 | "chip->phub_id_reg=%x, " |
179 | "chip->q_pri_val_reg=%x, " |
180 | "chip->rc_q_maxsize_reg=%x, " |
181 | "chip->bri_q_maxsize_reg=%x, " |
182 | "chip->comp_resp_timeout_reg=%x, " |
183 | "chip->bus_slave_control_reg=%x, " |
184 | "chip->deadlock_avoid_type_reg=%x, " |
185 | "chip->intpin_reg_wpermit_reg0=%x, " |
186 | "chip->intpin_reg_wpermit_reg1=%x, " |
187 | "chip->intpin_reg_wpermit_reg2=%x, " |
188 | "chip->intpin_reg_wpermit_reg3=%x\n" , __func__, |
189 | chip->phub_id_reg, |
190 | chip->q_pri_val_reg, |
191 | chip->rc_q_maxsize_reg, |
192 | chip->bri_q_maxsize_reg, |
193 | chip->comp_resp_timeout_reg, |
194 | chip->bus_slave_control_reg, |
195 | chip->deadlock_avoid_type_reg, |
196 | chip->intpin_reg_wpermit_reg0, |
197 | chip->intpin_reg_wpermit_reg1, |
198 | chip->intpin_reg_wpermit_reg2, |
199 | chip->intpin_reg_wpermit_reg3); |
200 | for (i = 0; i < MAX_NUM_INT_REDUCE_CONTROL_REG; i++) { |
201 | chip->int_reduce_control_reg[i] = |
202 | ioread32(p + PCH_PHUB_INT_REDUCE_CONTROL_REG_BASE + 4 * i); |
203 | dev_dbg(&pdev->dev, "%s : " |
204 | "chip->int_reduce_control_reg[%d]=%x\n" , |
205 | __func__, i, chip->int_reduce_control_reg[i]); |
206 | } |
207 | chip->clkcfg_reg = ioread32(p + CLKCFG_REG_OFFSET); |
208 | if ((chip->ioh_type == 2) || (chip->ioh_type == 4)) |
209 | chip->funcsel_reg = ioread32(p + FUNCSEL_REG_OFFSET); |
210 | } |
211 | |
212 | /* pch_phub_restore_reg_conf - restore register configuration */ |
213 | static void __maybe_unused pch_phub_restore_reg_conf(struct pci_dev *pdev) |
214 | { |
215 | unsigned int i; |
216 | struct pch_phub_reg *chip = pci_get_drvdata(pdev); |
217 | void __iomem *p; |
218 | p = chip->pch_phub_base_address; |
219 | |
220 | iowrite32(chip->phub_id_reg, p + PCH_PHUB_ID_REG); |
221 | iowrite32(chip->q_pri_val_reg, p + PCH_PHUB_QUEUE_PRI_VAL_REG); |
222 | iowrite32(chip->rc_q_maxsize_reg, p + PCH_PHUB_RC_QUEUE_MAXSIZE_REG); |
223 | iowrite32(chip->bri_q_maxsize_reg, p + PCH_PHUB_BRI_QUEUE_MAXSIZE_REG); |
224 | iowrite32(chip->comp_resp_timeout_reg, |
225 | p + PCH_PHUB_COMP_RESP_TIMEOUT_REG); |
226 | iowrite32(chip->bus_slave_control_reg, |
227 | p + PCH_PHUB_BUS_SLAVE_CONTROL_REG); |
228 | iowrite32(chip->deadlock_avoid_type_reg, |
229 | p + PCH_PHUB_DEADLOCK_AVOID_TYPE_REG); |
230 | iowrite32(chip->intpin_reg_wpermit_reg0, |
231 | p + PCH_PHUB_INTPIN_REG_WPERMIT_REG0); |
232 | iowrite32(chip->intpin_reg_wpermit_reg1, |
233 | p + PCH_PHUB_INTPIN_REG_WPERMIT_REG1); |
234 | iowrite32(chip->intpin_reg_wpermit_reg2, |
235 | p + PCH_PHUB_INTPIN_REG_WPERMIT_REG2); |
236 | iowrite32(chip->intpin_reg_wpermit_reg3, |
237 | p + PCH_PHUB_INTPIN_REG_WPERMIT_REG3); |
238 | dev_dbg(&pdev->dev, "%s : " |
239 | "chip->phub_id_reg=%x, " |
240 | "chip->q_pri_val_reg=%x, " |
241 | "chip->rc_q_maxsize_reg=%x, " |
242 | "chip->bri_q_maxsize_reg=%x, " |
243 | "chip->comp_resp_timeout_reg=%x, " |
244 | "chip->bus_slave_control_reg=%x, " |
245 | "chip->deadlock_avoid_type_reg=%x, " |
246 | "chip->intpin_reg_wpermit_reg0=%x, " |
247 | "chip->intpin_reg_wpermit_reg1=%x, " |
248 | "chip->intpin_reg_wpermit_reg2=%x, " |
249 | "chip->intpin_reg_wpermit_reg3=%x\n" , __func__, |
250 | chip->phub_id_reg, |
251 | chip->q_pri_val_reg, |
252 | chip->rc_q_maxsize_reg, |
253 | chip->bri_q_maxsize_reg, |
254 | chip->comp_resp_timeout_reg, |
255 | chip->bus_slave_control_reg, |
256 | chip->deadlock_avoid_type_reg, |
257 | chip->intpin_reg_wpermit_reg0, |
258 | chip->intpin_reg_wpermit_reg1, |
259 | chip->intpin_reg_wpermit_reg2, |
260 | chip->intpin_reg_wpermit_reg3); |
261 | for (i = 0; i < MAX_NUM_INT_REDUCE_CONTROL_REG; i++) { |
262 | iowrite32(chip->int_reduce_control_reg[i], |
263 | p + PCH_PHUB_INT_REDUCE_CONTROL_REG_BASE + 4 * i); |
264 | dev_dbg(&pdev->dev, "%s : " |
265 | "chip->int_reduce_control_reg[%d]=%x\n" , |
266 | __func__, i, chip->int_reduce_control_reg[i]); |
267 | } |
268 | |
269 | iowrite32(chip->clkcfg_reg, p + CLKCFG_REG_OFFSET); |
270 | if ((chip->ioh_type == 2) || (chip->ioh_type == 4)) |
271 | iowrite32(chip->funcsel_reg, p + FUNCSEL_REG_OFFSET); |
272 | } |
273 | |
274 | /** |
275 | * pch_phub_read_serial_rom() - Reading Serial ROM |
276 | * @chip: Pointer to the PHUB register structure |
277 | * @offset_address: Serial ROM offset address to read. |
278 | * @data: Read buffer for specified Serial ROM value. |
279 | */ |
280 | static void pch_phub_read_serial_rom(struct pch_phub_reg *chip, |
281 | unsigned int offset_address, u8 *data) |
282 | { |
283 | void __iomem *mem_addr = chip->pch_phub_extrom_base_address + |
284 | offset_address; |
285 | |
286 | *data = ioread8(mem_addr); |
287 | } |
288 | |
289 | /** |
290 | * pch_phub_write_serial_rom() - Writing Serial ROM |
291 | * @chip: Pointer to the PHUB register structure |
292 | * @offset_address: Serial ROM offset address. |
293 | * @data: Serial ROM value to write. |
294 | */ |
295 | static int pch_phub_write_serial_rom(struct pch_phub_reg *chip, |
296 | unsigned int offset_address, u8 data) |
297 | { |
298 | void __iomem *mem_addr = chip->pch_phub_extrom_base_address + |
299 | (offset_address & PCH_WORD_ADDR_MASK); |
300 | int i; |
301 | unsigned int word_data; |
302 | unsigned int pos; |
303 | unsigned int mask; |
304 | pos = (offset_address % 4) * 8; |
305 | mask = ~(0xFF << pos); |
306 | |
307 | iowrite32(PCH_PHUB_ROM_WRITE_ENABLE, |
308 | chip->pch_phub_extrom_base_address + PHUB_CONTROL); |
309 | |
310 | word_data = ioread32(mem_addr); |
311 | iowrite32((word_data & mask) | (u32)data << pos, mem_addr); |
312 | |
313 | i = 0; |
314 | while (ioread8(chip->pch_phub_extrom_base_address + |
315 | PHUB_STATUS) != 0x00) { |
316 | msleep(msecs: 1); |
317 | if (i == PHUB_TIMEOUT) |
318 | return -ETIMEDOUT; |
319 | i++; |
320 | } |
321 | |
322 | iowrite32(PCH_PHUB_ROM_WRITE_DISABLE, |
323 | chip->pch_phub_extrom_base_address + PHUB_CONTROL); |
324 | |
325 | return 0; |
326 | } |
327 | |
328 | /** |
329 | * pch_phub_read_serial_rom_val() - Read Serial ROM value |
330 | * @chip: Pointer to the PHUB register structure |
331 | * @offset_address: Serial ROM address offset value. |
332 | * @data: Serial ROM value to read. |
333 | */ |
334 | static void pch_phub_read_serial_rom_val(struct pch_phub_reg *chip, |
335 | unsigned int offset_address, u8 *data) |
336 | { |
337 | unsigned int mem_addr; |
338 | |
339 | mem_addr = chip->pch_mac_start_address + |
340 | pch_phub_mac_offset[offset_address]; |
341 | |
342 | pch_phub_read_serial_rom(chip, offset_address: mem_addr, data); |
343 | } |
344 | |
345 | /** |
346 | * pch_phub_write_serial_rom_val() - writing Serial ROM value |
347 | * @chip: Pointer to the PHUB register structure |
348 | * @offset_address: Serial ROM address offset value. |
349 | * @data: Serial ROM value. |
350 | */ |
351 | static int pch_phub_write_serial_rom_val(struct pch_phub_reg *chip, |
352 | unsigned int offset_address, u8 data) |
353 | { |
354 | int retval; |
355 | unsigned int mem_addr; |
356 | |
357 | mem_addr = chip->pch_mac_start_address + |
358 | pch_phub_mac_offset[offset_address]; |
359 | |
360 | retval = pch_phub_write_serial_rom(chip, offset_address: mem_addr, data); |
361 | |
362 | return retval; |
363 | } |
364 | |
365 | /* pch_phub_gbe_serial_rom_conf - makes Serial ROM header format configuration |
366 | * for Gigabit Ethernet MAC address |
367 | */ |
368 | static int pch_phub_gbe_serial_rom_conf(struct pch_phub_reg *chip) |
369 | { |
370 | int retval; |
371 | |
372 | retval = pch_phub_write_serial_rom(chip, offset_address: 0x0b, data: 0xbc); |
373 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x0a, data: 0x10); |
374 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x09, data: 0x01); |
375 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x08, data: 0x02); |
376 | |
377 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x0f, data: 0x00); |
378 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x0e, data: 0x00); |
379 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x0d, data: 0x00); |
380 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x0c, data: 0x80); |
381 | |
382 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x13, data: 0xbc); |
383 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x12, data: 0x10); |
384 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x11, data: 0x01); |
385 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x10, data: 0x18); |
386 | |
387 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x1b, data: 0xbc); |
388 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x1a, data: 0x10); |
389 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x19, data: 0x01); |
390 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x18, data: 0x19); |
391 | |
392 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x23, data: 0xbc); |
393 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x22, data: 0x10); |
394 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x21, data: 0x01); |
395 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x20, data: 0x3a); |
396 | |
397 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x27, data: 0x01); |
398 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x26, data: 0x00); |
399 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x25, data: 0x00); |
400 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x24, data: 0x00); |
401 | |
402 | return retval; |
403 | } |
404 | |
405 | /* pch_phub_gbe_serial_rom_conf_mp - makes SerialROM header format configuration |
406 | * for Gigabit Ethernet MAC address |
407 | */ |
408 | static int pch_phub_gbe_serial_rom_conf_mp(struct pch_phub_reg *chip) |
409 | { |
410 | int retval; |
411 | u32 offset_addr; |
412 | |
413 | offset_addr = 0x200; |
414 | retval = pch_phub_write_serial_rom(chip, offset_address: 0x03 + offset_addr, data: 0xbc); |
415 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x02 + offset_addr, data: 0x00); |
416 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x01 + offset_addr, data: 0x40); |
417 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x00 + offset_addr, data: 0x02); |
418 | |
419 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x07 + offset_addr, data: 0x00); |
420 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x06 + offset_addr, data: 0x00); |
421 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x05 + offset_addr, data: 0x00); |
422 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x04 + offset_addr, data: 0x80); |
423 | |
424 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x0b + offset_addr, data: 0xbc); |
425 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x0a + offset_addr, data: 0x00); |
426 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x09 + offset_addr, data: 0x40); |
427 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x08 + offset_addr, data: 0x18); |
428 | |
429 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x13 + offset_addr, data: 0xbc); |
430 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x12 + offset_addr, data: 0x00); |
431 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x11 + offset_addr, data: 0x40); |
432 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x10 + offset_addr, data: 0x19); |
433 | |
434 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x1b + offset_addr, data: 0xbc); |
435 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x1a + offset_addr, data: 0x00); |
436 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x19 + offset_addr, data: 0x40); |
437 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x18 + offset_addr, data: 0x3a); |
438 | |
439 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x1f + offset_addr, data: 0x01); |
440 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x1e + offset_addr, data: 0x00); |
441 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x1d + offset_addr, data: 0x00); |
442 | retval |= pch_phub_write_serial_rom(chip, offset_address: 0x1c + offset_addr, data: 0x00); |
443 | |
444 | return retval; |
445 | } |
446 | |
447 | /** |
448 | * pch_phub_read_gbe_mac_addr() - Read Gigabit Ethernet MAC address |
449 | * @chip: Pointer to the PHUB register structure |
450 | * @data: Buffer of the Gigabit Ethernet MAC address value. |
451 | */ |
452 | static void pch_phub_read_gbe_mac_addr(struct pch_phub_reg *chip, u8 *data) |
453 | { |
454 | int i; |
455 | for (i = 0; i < ETH_ALEN; i++) |
456 | pch_phub_read_serial_rom_val(chip, offset_address: i, data: &data[i]); |
457 | } |
458 | |
459 | /** |
460 | * pch_phub_write_gbe_mac_addr() - Write MAC address |
461 | * @chip: Pointer to the PHUB register structure |
462 | * @data: Gigabit Ethernet MAC address value. |
463 | */ |
464 | static int pch_phub_write_gbe_mac_addr(struct pch_phub_reg *chip, u8 *data) |
465 | { |
466 | int retval; |
467 | int i; |
468 | |
469 | if ((chip->ioh_type == 1) || (chip->ioh_type == 5)) /* EG20T or ML7831*/ |
470 | retval = pch_phub_gbe_serial_rom_conf(chip); |
471 | else /* ML7223 */ |
472 | retval = pch_phub_gbe_serial_rom_conf_mp(chip); |
473 | if (retval) |
474 | return retval; |
475 | |
476 | for (i = 0; i < ETH_ALEN; i++) { |
477 | retval = pch_phub_write_serial_rom_val(chip, offset_address: i, data: data[i]); |
478 | if (retval) |
479 | return retval; |
480 | } |
481 | |
482 | return retval; |
483 | } |
484 | |
485 | static ssize_t pch_phub_bin_read(struct file *filp, struct kobject *kobj, |
486 | struct bin_attribute *attr, char *buf, |
487 | loff_t off, size_t count) |
488 | { |
489 | unsigned int rom_signature; |
490 | unsigned char rom_length; |
491 | unsigned int tmp; |
492 | unsigned int addr_offset; |
493 | unsigned int orom_size; |
494 | int ret; |
495 | int err; |
496 | ssize_t rom_size; |
497 | |
498 | struct pch_phub_reg *chip = dev_get_drvdata(kobj_to_dev(kobj)); |
499 | |
500 | ret = mutex_lock_interruptible(&pch_phub_mutex); |
501 | if (ret) { |
502 | err = -ERESTARTSYS; |
503 | goto return_err_nomutex; |
504 | } |
505 | |
506 | /* Get Rom signature */ |
507 | chip->pch_phub_extrom_base_address = pci_map_rom(pdev: chip->pdev, size: &rom_size); |
508 | if (!chip->pch_phub_extrom_base_address) { |
509 | err = -ENODATA; |
510 | goto exrom_map_err; |
511 | } |
512 | |
513 | pch_phub_read_serial_rom(chip, offset_address: chip->pch_opt_rom_start_address, |
514 | data: (unsigned char *)&rom_signature); |
515 | rom_signature &= 0xff; |
516 | pch_phub_read_serial_rom(chip, offset_address: chip->pch_opt_rom_start_address + 1, |
517 | data: (unsigned char *)&tmp); |
518 | rom_signature |= (tmp & 0xff) << 8; |
519 | if (rom_signature == 0xAA55) { |
520 | pch_phub_read_serial_rom(chip, |
521 | offset_address: chip->pch_opt_rom_start_address + 2, |
522 | data: &rom_length); |
523 | orom_size = rom_length * 512; |
524 | if (orom_size < off) { |
525 | addr_offset = 0; |
526 | goto return_ok; |
527 | } |
528 | if (orom_size < count) { |
529 | addr_offset = 0; |
530 | goto return_ok; |
531 | } |
532 | |
533 | for (addr_offset = 0; addr_offset < count; addr_offset++) { |
534 | pch_phub_read_serial_rom(chip, |
535 | offset_address: chip->pch_opt_rom_start_address + addr_offset + off, |
536 | data: &buf[addr_offset]); |
537 | } |
538 | } else { |
539 | err = -ENODATA; |
540 | goto return_err; |
541 | } |
542 | return_ok: |
543 | pci_unmap_rom(pdev: chip->pdev, rom: chip->pch_phub_extrom_base_address); |
544 | mutex_unlock(lock: &pch_phub_mutex); |
545 | return addr_offset; |
546 | |
547 | return_err: |
548 | pci_unmap_rom(pdev: chip->pdev, rom: chip->pch_phub_extrom_base_address); |
549 | exrom_map_err: |
550 | mutex_unlock(lock: &pch_phub_mutex); |
551 | return_err_nomutex: |
552 | return err; |
553 | } |
554 | |
555 | static ssize_t pch_phub_bin_write(struct file *filp, struct kobject *kobj, |
556 | struct bin_attribute *attr, |
557 | char *buf, loff_t off, size_t count) |
558 | { |
559 | int err; |
560 | unsigned int addr_offset; |
561 | int ret; |
562 | ssize_t rom_size; |
563 | struct pch_phub_reg *chip = dev_get_drvdata(kobj_to_dev(kobj)); |
564 | |
565 | ret = mutex_lock_interruptible(&pch_phub_mutex); |
566 | if (ret) |
567 | return -ERESTARTSYS; |
568 | |
569 | if (off > PCH_PHUB_OROM_SIZE) { |
570 | addr_offset = 0; |
571 | goto return_ok; |
572 | } |
573 | if (count > PCH_PHUB_OROM_SIZE) { |
574 | addr_offset = 0; |
575 | goto return_ok; |
576 | } |
577 | |
578 | chip->pch_phub_extrom_base_address = pci_map_rom(pdev: chip->pdev, size: &rom_size); |
579 | if (!chip->pch_phub_extrom_base_address) { |
580 | err = -ENOMEM; |
581 | goto exrom_map_err; |
582 | } |
583 | |
584 | for (addr_offset = 0; addr_offset < count; addr_offset++) { |
585 | if (PCH_PHUB_OROM_SIZE < off + addr_offset) |
586 | goto return_ok; |
587 | |
588 | ret = pch_phub_write_serial_rom(chip, |
589 | offset_address: chip->pch_opt_rom_start_address + addr_offset + off, |
590 | data: buf[addr_offset]); |
591 | if (ret) { |
592 | err = ret; |
593 | goto return_err; |
594 | } |
595 | } |
596 | |
597 | return_ok: |
598 | pci_unmap_rom(pdev: chip->pdev, rom: chip->pch_phub_extrom_base_address); |
599 | mutex_unlock(lock: &pch_phub_mutex); |
600 | return addr_offset; |
601 | |
602 | return_err: |
603 | pci_unmap_rom(pdev: chip->pdev, rom: chip->pch_phub_extrom_base_address); |
604 | |
605 | exrom_map_err: |
606 | mutex_unlock(lock: &pch_phub_mutex); |
607 | return err; |
608 | } |
609 | |
610 | static ssize_t show_pch_mac(struct device *dev, struct device_attribute *attr, |
611 | char *buf) |
612 | { |
613 | u8 mac[8]; |
614 | struct pch_phub_reg *chip = dev_get_drvdata(dev); |
615 | ssize_t rom_size; |
616 | |
617 | chip->pch_phub_extrom_base_address = pci_map_rom(pdev: chip->pdev, size: &rom_size); |
618 | if (!chip->pch_phub_extrom_base_address) |
619 | return -ENOMEM; |
620 | |
621 | pch_phub_read_gbe_mac_addr(chip, data: mac); |
622 | pci_unmap_rom(pdev: chip->pdev, rom: chip->pch_phub_extrom_base_address); |
623 | |
624 | return sprintf(buf, fmt: "%pM\n" , mac); |
625 | } |
626 | |
627 | static ssize_t store_pch_mac(struct device *dev, struct device_attribute *attr, |
628 | const char *buf, size_t count) |
629 | { |
630 | u8 mac[ETH_ALEN]; |
631 | ssize_t rom_size; |
632 | struct pch_phub_reg *chip = dev_get_drvdata(dev); |
633 | int ret; |
634 | |
635 | if (!mac_pton(s: buf, mac)) |
636 | return -EINVAL; |
637 | |
638 | chip->pch_phub_extrom_base_address = pci_map_rom(pdev: chip->pdev, size: &rom_size); |
639 | if (!chip->pch_phub_extrom_base_address) |
640 | return -ENOMEM; |
641 | |
642 | ret = pch_phub_write_gbe_mac_addr(chip, data: mac); |
643 | pci_unmap_rom(pdev: chip->pdev, rom: chip->pch_phub_extrom_base_address); |
644 | if (ret) |
645 | return ret; |
646 | |
647 | return count; |
648 | } |
649 | |
650 | static DEVICE_ATTR(pch_mac, S_IRUGO | S_IWUSR, show_pch_mac, store_pch_mac); |
651 | |
652 | static const struct bin_attribute pch_bin_attr = { |
653 | .attr = { |
654 | .name = "pch_firmware" , |
655 | .mode = S_IRUGO | S_IWUSR, |
656 | }, |
657 | .size = PCH_PHUB_OROM_SIZE + 1, |
658 | .read = pch_phub_bin_read, |
659 | .write = pch_phub_bin_write, |
660 | }; |
661 | |
662 | static int pch_phub_probe(struct pci_dev *pdev, |
663 | const struct pci_device_id *id) |
664 | { |
665 | int ret; |
666 | struct pch_phub_reg *chip; |
667 | |
668 | chip = kzalloc(size: sizeof(struct pch_phub_reg), GFP_KERNEL); |
669 | if (chip == NULL) |
670 | return -ENOMEM; |
671 | |
672 | ret = pci_enable_device(dev: pdev); |
673 | if (ret) { |
674 | dev_err(&pdev->dev, |
675 | "%s : pci_enable_device FAILED(ret=%d)" , __func__, ret); |
676 | goto err_pci_enable_dev; |
677 | } |
678 | dev_dbg(&pdev->dev, "%s : pci_enable_device returns %d\n" , __func__, |
679 | ret); |
680 | |
681 | ret = pci_request_regions(pdev, KBUILD_MODNAME); |
682 | if (ret) { |
683 | dev_err(&pdev->dev, |
684 | "%s : pci_request_regions FAILED(ret=%d)" , __func__, ret); |
685 | goto err_req_regions; |
686 | } |
687 | dev_dbg(&pdev->dev, "%s : " |
688 | "pci_request_regions returns %d\n" , __func__, ret); |
689 | |
690 | chip->pch_phub_base_address = pci_iomap(dev: pdev, bar: 1, max: 0); |
691 | |
692 | |
693 | if (chip->pch_phub_base_address == NULL) { |
694 | dev_err(&pdev->dev, "%s : pci_iomap FAILED" , __func__); |
695 | ret = -ENOMEM; |
696 | goto err_pci_iomap; |
697 | } |
698 | dev_dbg(&pdev->dev, "%s : pci_iomap SUCCESS and value " |
699 | "in pch_phub_base_address variable is %p\n" , __func__, |
700 | chip->pch_phub_base_address); |
701 | |
702 | chip->pdev = pdev; /* Save pci device struct */ |
703 | |
704 | if (id->driver_data == 1) { /* EG20T PCH */ |
705 | const char *board_name; |
706 | unsigned int prefetch = 0x000affaa; |
707 | |
708 | if (pdev->dev.of_node) |
709 | of_property_read_u32(np: pdev->dev.of_node, |
710 | propname: "intel,eg20t-prefetch" , |
711 | out_value: &prefetch); |
712 | |
713 | ret = sysfs_create_file(kobj: &pdev->dev.kobj, |
714 | attr: &dev_attr_pch_mac.attr); |
715 | if (ret) |
716 | goto err_sysfs_create; |
717 | |
718 | ret = sysfs_create_bin_file(kobj: &pdev->dev.kobj, attr: &pch_bin_attr); |
719 | if (ret) |
720 | goto exit_bin_attr; |
721 | |
722 | pch_phub_read_modify_write_reg(chip, |
723 | reg_addr_offset: (unsigned int)CLKCFG_REG_OFFSET, |
724 | CLKCFG_CAN_50MHZ, |
725 | CLKCFG_CANCLK_MASK); |
726 | |
727 | /* quirk for CM-iTC board */ |
728 | board_name = dmi_get_system_info(field: DMI_BOARD_NAME); |
729 | if (board_name && strstr(board_name, "CM-iTC" )) |
730 | pch_phub_read_modify_write_reg(chip, |
731 | reg_addr_offset: (unsigned int)CLKCFG_REG_OFFSET, |
732 | CLKCFG_UART_48MHZ | CLKCFG_BAUDDIV | |
733 | CLKCFG_PLL2VCO | CLKCFG_UARTCLKSEL, |
734 | CLKCFG_UART_MASK); |
735 | |
736 | /* set the prefech value */ |
737 | iowrite32(prefetch, chip->pch_phub_base_address + 0x14); |
738 | /* set the interrupt delay value */ |
739 | iowrite32(0x25, chip->pch_phub_base_address + 0x44); |
740 | chip->pch_opt_rom_start_address = PCH_PHUB_ROM_START_ADDR_EG20T; |
741 | chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_EG20T; |
742 | |
743 | /* quirk for MIPS Boston platform */ |
744 | if (pdev->dev.of_node) { |
745 | if (of_machine_is_compatible(compat: "img,boston" )) { |
746 | pch_phub_read_modify_write_reg(chip, |
747 | reg_addr_offset: (unsigned int)CLKCFG_REG_OFFSET, |
748 | CLKCFG_UART_25MHZ, |
749 | CLKCFG_UART_MASK); |
750 | } |
751 | } |
752 | } else if (id->driver_data == 2) { /* ML7213 IOH */ |
753 | ret = sysfs_create_bin_file(kobj: &pdev->dev.kobj, attr: &pch_bin_attr); |
754 | if (ret) |
755 | goto err_sysfs_create; |
756 | /* set the prefech value |
757 | * Device2(USB OHCI #1/ USB EHCI #1/ USB Device):a |
758 | * Device4(SDIO #0,1,2):f |
759 | * Device6(SATA 2):f |
760 | * Device8(USB OHCI #0/ USB EHCI #0):a |
761 | */ |
762 | iowrite32(0x000affa0, chip->pch_phub_base_address + 0x14); |
763 | chip->pch_opt_rom_start_address =\ |
764 | PCH_PHUB_ROM_START_ADDR_ML7213; |
765 | } else if (id->driver_data == 3) { /* ML7223 IOH Bus-m*/ |
766 | /* set the prefech value |
767 | * Device8(GbE) |
768 | */ |
769 | iowrite32(0x000a0000, chip->pch_phub_base_address + 0x14); |
770 | /* set the interrupt delay value */ |
771 | iowrite32(0x25, chip->pch_phub_base_address + 0x140); |
772 | chip->pch_opt_rom_start_address =\ |
773 | PCH_PHUB_ROM_START_ADDR_ML7223; |
774 | chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_ML7223; |
775 | } else if (id->driver_data == 4) { /* ML7223 IOH Bus-n*/ |
776 | ret = sysfs_create_file(kobj: &pdev->dev.kobj, |
777 | attr: &dev_attr_pch_mac.attr); |
778 | if (ret) |
779 | goto err_sysfs_create; |
780 | ret = sysfs_create_bin_file(kobj: &pdev->dev.kobj, attr: &pch_bin_attr); |
781 | if (ret) |
782 | goto exit_bin_attr; |
783 | /* set the prefech value |
784 | * Device2(USB OHCI #0,1,2,3/ USB EHCI #0):a |
785 | * Device4(SDIO #0,1):f |
786 | * Device6(SATA 2):f |
787 | */ |
788 | iowrite32(0x0000ffa0, chip->pch_phub_base_address + 0x14); |
789 | chip->pch_opt_rom_start_address =\ |
790 | PCH_PHUB_ROM_START_ADDR_ML7223; |
791 | chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_ML7223; |
792 | } else if (id->driver_data == 5) { /* ML7831 */ |
793 | ret = sysfs_create_file(kobj: &pdev->dev.kobj, |
794 | attr: &dev_attr_pch_mac.attr); |
795 | if (ret) |
796 | goto err_sysfs_create; |
797 | |
798 | ret = sysfs_create_bin_file(kobj: &pdev->dev.kobj, attr: &pch_bin_attr); |
799 | if (ret) |
800 | goto exit_bin_attr; |
801 | |
802 | /* set the prefech value */ |
803 | iowrite32(0x000affaa, chip->pch_phub_base_address + 0x14); |
804 | /* set the interrupt delay value */ |
805 | iowrite32(0x25, chip->pch_phub_base_address + 0x44); |
806 | chip->pch_opt_rom_start_address = PCH_PHUB_ROM_START_ADDR_EG20T; |
807 | chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_EG20T; |
808 | } |
809 | |
810 | chip->ioh_type = id->driver_data; |
811 | pci_set_drvdata(pdev, data: chip); |
812 | |
813 | return 0; |
814 | exit_bin_attr: |
815 | sysfs_remove_file(kobj: &pdev->dev.kobj, attr: &dev_attr_pch_mac.attr); |
816 | |
817 | err_sysfs_create: |
818 | pci_iounmap(dev: pdev, chip->pch_phub_base_address); |
819 | err_pci_iomap: |
820 | pci_release_regions(pdev); |
821 | err_req_regions: |
822 | pci_disable_device(dev: pdev); |
823 | err_pci_enable_dev: |
824 | kfree(objp: chip); |
825 | dev_err(&pdev->dev, "%s returns %d\n" , __func__, ret); |
826 | return ret; |
827 | } |
828 | |
829 | static void pch_phub_remove(struct pci_dev *pdev) |
830 | { |
831 | struct pch_phub_reg *chip = pci_get_drvdata(pdev); |
832 | |
833 | sysfs_remove_file(kobj: &pdev->dev.kobj, attr: &dev_attr_pch_mac.attr); |
834 | sysfs_remove_bin_file(kobj: &pdev->dev.kobj, attr: &pch_bin_attr); |
835 | pci_iounmap(dev: pdev, chip->pch_phub_base_address); |
836 | pci_release_regions(pdev); |
837 | pci_disable_device(dev: pdev); |
838 | kfree(objp: chip); |
839 | } |
840 | |
841 | static int __maybe_unused pch_phub_suspend(struct device *dev_d) |
842 | { |
843 | device_wakeup_disable(dev: dev_d); |
844 | |
845 | return 0; |
846 | } |
847 | |
848 | static int __maybe_unused pch_phub_resume(struct device *dev_d) |
849 | { |
850 | device_wakeup_disable(dev: dev_d); |
851 | |
852 | return 0; |
853 | } |
854 | |
855 | static const struct pci_device_id pch_phub_pcidev_id[] = { |
856 | { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH1_PHUB), 1, }, |
857 | { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7213_PHUB), 2, }, |
858 | { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7223_mPHUB), 3, }, |
859 | { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7223_nPHUB), 4, }, |
860 | { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7831_PHUB), 5, }, |
861 | { } |
862 | }; |
863 | MODULE_DEVICE_TABLE(pci, pch_phub_pcidev_id); |
864 | |
865 | static SIMPLE_DEV_PM_OPS(pch_phub_pm_ops, pch_phub_suspend, pch_phub_resume); |
866 | |
867 | static struct pci_driver pch_phub_driver = { |
868 | .name = "pch_phub" , |
869 | .id_table = pch_phub_pcidev_id, |
870 | .probe = pch_phub_probe, |
871 | .remove = pch_phub_remove, |
872 | .driver.pm = &pch_phub_pm_ops, |
873 | }; |
874 | |
875 | module_pci_driver(pch_phub_driver); |
876 | |
877 | MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7223) PHUB" ); |
878 | MODULE_LICENSE("GPL" ); |
879 | |