2 * Initialize Owl Emulation Devices
4 * Copyright (C) 2016 Christian Lamparter <chunkeey@googlemail.com>
5 * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published
9 * by the Free Software Foundation.
11 * Some devices (like the Cisco Meraki Z1 Cloud Managed Teleworker Gateway)
12 * need to be able to initialize the PCIe wifi device. Normally, this is done
13 * during the early stages of booting linux, because the necessary init code
14 * is read from the memory mapped SPI and passed to pci_enable_ath9k_fixup.
15 * However,this isn't possible for devices which have the init code for the
16 * Atheros chip stored on NAND. Hence, this module can be used to initialze
17 * the chip when the user-space is ready to extract the init code.
19 #include <linux/module.h>
20 #include <linux/version.h>
21 #include <linux/completion.h>
22 #include <linux/etherdevice.h>
23 #include <linux/firmware.h>
24 #include <linux/pci.h>
25 #include <linux/delay.h>
26 #include <linux/platform_device.h>
27 #include <linux/ath9k_platform.h>
30 struct completion eeprom_load
;
33 #define EEPROM_FILENAME_LEN 100
35 #define AR5416_EEPROM_MAGIC 0xa55a
37 static int ath9k_pci_fixup(struct pci_dev
*pdev
, const u16
*cal_data
,
41 const void *cal_end
= (void *)cal_data
+ cal_len
;
49 bool swap_needed
= false;
51 if (*cal_data
!= AR5416_EEPROM_MAGIC
) {
52 if (*cal_data
!= swab16(AR5416_EEPROM_MAGIC
)) {
53 dev_err(&pdev
->dev
, "invalid calibration data\n");
57 dev_dbg(&pdev
->dev
, "calibration data needs swapping\n");
61 dev_info(&pdev
->dev
, "fixup device configuration\n");
63 mem
= pcim_iomap(pdev
, 0, 0);
65 dev_err(&pdev
->dev
, "ioremap error\n");
69 pci_read_config_dword(pdev
, PCI_BASE_ADDRESS_0
, &bar0
);
70 pci_write_config_dword(pdev
, PCI_BASE_ADDRESS_0
,
71 pci_resource_start(pdev
, 0));
72 pci_read_config_word(pdev
, PCI_COMMAND
, &cmd
);
73 cmd
|= PCI_COMMAND_MASTER
| PCI_COMMAND_MEMORY
;
74 pci_write_config_word(pdev
, PCI_COMMAND
, cmd
);
76 /* set pointer to first reg address */
77 for (data
= (const void *) (cal_data
+ 3);
78 (const void *) data
<= cal_end
&& data
->reg
!= cpu_to_be16(~0);
85 val
|= data
->high_val
<< 16;
96 __raw_writel(val
, mem
+ reg
);
100 pci_read_config_word(pdev
, PCI_COMMAND
, &cmd
);
101 cmd
&= ~(PCI_COMMAND_MASTER
| PCI_COMMAND_MEMORY
);
102 pci_write_config_word(pdev
, PCI_COMMAND
, cmd
);
104 pci_write_config_dword(pdev
, PCI_BASE_ADDRESS_0
, bar0
);
105 pcim_iounmap(pdev
, mem
);
107 pci_disable_device(pdev
);
112 static void owl_fw_cb(const struct firmware
*fw
, void *context
)
114 struct pci_dev
*pdev
= (struct pci_dev
*) context
;
115 struct owl_ctx
*ctx
= (struct owl_ctx
*) pci_get_drvdata(pdev
);
116 struct ath9k_platform_data
*pdata
= dev_get_platdata(&pdev
->dev
);
119 complete(&ctx
->eeprom_load
);
122 dev_err(&pdev
->dev
, "no eeprom data received.\n");
126 /* also note that we are doing *u16 operations on the file */
127 if (fw
->size
> sizeof(pdata
->eeprom_data
) || fw
->size
< 0x200 ||
128 (fw
->size
& 1) == 1) {
129 dev_err(&pdev
->dev
, "eeprom file has an invalid size.\n");
134 memcpy(pdata
->eeprom_data
, fw
->data
, fw
->size
);
137 * eeprom has been successfully loaded - pass the data to ath9k
138 * but remove the eeprom_name, so it doesn't try to load it too.
140 pdata
->eeprom_name
= NULL
;
143 if (ath9k_pci_fixup(pdev
, (const u16
*) fw
->data
, fw
->size
))
146 pci_lock_rescan_remove();
148 pci_stop_and_remove_bus_device(pdev
);
150 * the device should come back with the proper
151 * ProductId. But we have to initiate a rescan.
154 pci_unlock_rescan_remove();
157 release_firmware(fw
);
160 static const char *owl_get_eeprom_name(struct pci_dev
*pdev
)
162 struct device
*dev
= &pdev
->dev
;
163 struct ath9k_platform_data
*pdata
;
166 /* try the existing platform data first */
167 pdata
= dev_get_platdata(dev
);
168 if (pdata
&& pdata
->eeprom_name
)
169 return pdata
->eeprom_name
;
171 dev_dbg(dev
, "using auto-generated eeprom filename\n");
173 eeprom_name
= devm_kzalloc(dev
, EEPROM_FILENAME_LEN
, GFP_KERNEL
);
177 /* this should match the pattern used in ath9k/init.c */
178 scnprintf(eeprom_name
, EEPROM_FILENAME_LEN
, "ath9k-eeprom-pci-%s.bin",
184 static int owl_probe(struct pci_dev
*pdev
,
185 const struct pci_device_id
*id
)
188 const char *eeprom_name
;
191 if (pcim_enable_device(pdev
))
194 pcim_pin_device(pdev
);
196 eeprom_name
= owl_get_eeprom_name(pdev
);
198 dev_err(&pdev
->dev
, "no eeprom filename found.\n");
202 ctx
= kzalloc(sizeof(*ctx
), GFP_KERNEL
);
204 dev_err(&pdev
->dev
, "failed to alloc device context.\n");
207 init_completion(&ctx
->eeprom_load
);
209 pci_set_drvdata(pdev
, ctx
);
210 err
= request_firmware_nowait(THIS_MODULE
, true, eeprom_name
,
211 &pdev
->dev
, GFP_KERNEL
, pdev
, owl_fw_cb
);
213 dev_err(&pdev
->dev
, "failed to request caldata (%d).\n", err
);
219 static void owl_remove(struct pci_dev
*pdev
)
221 struct owl_ctx
*ctx
= pci_get_drvdata(pdev
);
224 wait_for_completion(&ctx
->eeprom_load
);
225 pci_set_drvdata(pdev
, NULL
);
230 static const struct pci_device_id owl_pci_table
[] = {
231 { PCI_VDEVICE(ATHEROS
, 0xff1c) }, /* PCIe */
232 { PCI_VDEVICE(ATHEROS
, 0xff1d) }, /* PCI */
235 MODULE_DEVICE_TABLE(pci
, owl_pci_table
);
237 static struct pci_driver owl_driver
= {
238 .name
= "owl-loader",
239 .id_table
= owl_pci_table
,
241 .remove
= owl_remove
,
243 module_pci_driver(owl_driver
);
244 MODULE_AUTHOR("Christian Lamparter <chunkeey@googlemail.com>");
245 MODULE_DESCRIPTION("Initializes Atheros' Owl Emulation devices");
246 MODULE_LICENSE("GPL v2");