Commit 4fe1ede4 authored by Miguel Jimenez Lopez's avatar Miguel Jimenez Lopez

kernel: Changes for the new WR Starting Kit project.

- Update the IRQ mechanism to use an external VIC driver.
- Create SysCon fields in the spec_dev structure to remove old dependency with golden gateware.
- Call new SDB scan functionalities.
parent 0ec1f9bc
......@@ -24,8 +24,9 @@ obj-m += spec.o
spec-y = spec-pci.o
spec-y += spec-fmc.o
spec-y += spec-irq.o
spec-y += spec-sdb-scan.o
spec-y += spec-i2c.o
spec-y += loader-ll.o
spec-y += spec-gpio-no.o
spec-$(CONFIG_GPIOLIB) += spec-gpio.o
\ No newline at end of file
spec-$(CONFIG_GPIOLIB) += spec-gpio.o
This diff is collapsed.
......@@ -47,25 +47,32 @@ static void dumpstruct(char *name, void *ptr, int size)
static void set_sda(struct fmc_device *fmc, int val)
{
struct spec_dev *spec = fmc->carrier_data;
unsigned long syscon_addr = spec->syscon_addr;
if (val)
fmc_writel(fmc, SYSC_GPSR_FMC_SDA, SYSC_REG_GPSR);
fmc_writel(fmc, SYSC_GPSR_FMC_SDA, syscon_addr+SYSC_REG_GPSR);
else
fmc_writel(fmc, SYSC_GPCR_FMC_SDA, SYSC_REG_GPCR);
fmc_writel(fmc, SYSC_GPCR_FMC_SDA, syscon_addr+SYSC_REG_GPCR);
ndelay(1250); /* 400kHz -> 2.5us/loop */
}
static void set_scl(struct fmc_device *fmc, int val)
{
struct spec_dev *spec = fmc->carrier_data;
unsigned long syscon_addr = spec->syscon_addr;
if (val)
fmc_writel(fmc, SYSC_GPSR_FMC_SCL, SYSC_REG_GPSR);
fmc_writel(fmc, SYSC_GPSR_FMC_SCL, syscon_addr+SYSC_REG_GPSR);
else
fmc_writel(fmc, SYSC_GPCR_FMC_SCL, SYSC_REG_GPCR);
fmc_writel(fmc, SYSC_GPCR_FMC_SCL, syscon_addr+SYSC_REG_GPCR);
ndelay(1250); /* 400kHz -> 2.5us/loop */
}
static int get_sda(struct fmc_device *fmc)
{
return fmc_readl(fmc, SYSC_REG_GPSR) & SYSC_GPSR_FMC_SDA ? 1 : 0;
struct spec_dev *spec = fmc->carrier_data;
unsigned long syscon_addr = spec->syscon_addr;
return fmc_readl(fmc, syscon_addr+SYSC_REG_GPSR) & SYSC_GPSR_FMC_SDA ? 1 : 0;
};
static void mi2c_start(struct fmc_device *fmc)
......
This diff is collapsed.
......@@ -6,6 +6,7 @@
*
*/
#include <linux/firmware.h>
#include <linux/types.h>
#include <linux/platform_device.h>
#include <linux/fmc.h>
......@@ -16,6 +17,8 @@
/*
* SDB information for several FPGA IP blocks.
*/
// SDB MAGIC
#define SDB_MAGIC 0x5344422d
// CERN devices
// Vendor
#define SDB_CERN_VENDOR 0x0000ce42
......@@ -43,6 +46,19 @@
#define SDB_DIO_PID 0x00000001
#define SDB_DIO_NAME "DIO"
// Designs entry points, bitstreams and firmware files
#define SPEC_GOLDEN_GW_NAME "fmc/spec-init.bin"
#define SDB_SPEC_GOLDEN_ENTRY 0x100
#define DIO_GW_NAME "fmc/wr_nic_dio.bin"
#define SDB_NIC_DIO_ENTRY 0x70000
#define NIC_GW_NAME "fmc/wr_nic.bin"
#define SDB_NIC_ENTRY 0x70000
#define NIC_LM32_FW_NAME "fmc/wr_nic_lm32_sw.bin"
// Misc
#define RAM_MAGIC 0x98000000
#define SYSCON_RESET_ON 0x1deadbee
#define SYSCON_RESET_OFF 0x0deadbee
/**
* @brief FPGA IP block structure.
*
......@@ -186,7 +202,6 @@ static int spec_sdb_fpga_dev_register(struct fmc_device *fmc, struct fpga_dev *f
unsigned long size;
struct resource *res = NULL;
struct spec_dev *spec = fmc->carrier_data;
unsigned int irq = spec->pdev->irq;
int i, j, r;
unsigned int n_irqs = 0;
unsigned int n_res = 0;
......@@ -306,3 +321,143 @@ void spec_sdb_fpga_dev_release_all(struct fmc_device *fmc)
return;
}
/**
* Initialize SDB structure for the FMC device.
*
* @param fmc FMC device
*
* @return 0 if success and a negative error code otherwise
*/
int spec_sdb_load(struct fmc_device *fmc)
{
struct spec_dev *spec = fmc->carrier_data;
unsigned long sdb_entry = spec->sdb_entry;
int ret;
/* poor man's SDB */
if (fmc_readl(fmc, sdb_entry) != SDB_MAGIC) {
dev_err(&spec->pdev->dev, "Can't find SDB magic\n");
return -ENODEV;
}
ret = fmc_scan_sdb_tree(fmc, sdb_entry);
if (ret < 0)
return -ENODEV;
spec->syscon_addr = fmc_find_sdb_device(fmc->sdb,
SDB_CERN_VENDOR, SDB_SYSCON_PID,
&spec->syscon_size);
if(spec->syscon_addr < 0)
return -ENODEV;
/* It is not a golden gateware, mark it. */
if(sdb_entry != SDB_SPEC_GOLDEN_ENTRY)
fmc->flags |= FMC_DEVICE_HAS_CUSTOM;
return 0;
}
/**
* Write LM32 RAM.
*
* @param fmc FMC device
* @param name LM32 firmware name
* @param ram Physical address for LM32 RAM
* @param ramsize Physical size for LM32 RAM
*
* @return 0 if success and a negative error code otherwise
*/
static int spec_lm32_fw_load(struct fmc_device *fmc, char *name,
unsigned long ram, unsigned long ramsize)
{
const struct firmware *fw;
struct device *dev = fmc->hwdev;
int ret, count;
const uint32_t *p;
ret = request_firmware(&fw, name, dev);
if (ret < 0) {
dev_err(dev, "request firmware \"%s\": error %i\n",
name, ret);
return ret;
}
if (fw->size > ramsize) {
dev_err(dev, "firmware \"%s\" longer than ram (0x%lx)\n",
name, ramsize);
ret = -ENOMEM;
goto out;
}
for (count = 0, p = (void *)fw->data; count < fw->size; count += 4, p++)
fmc_writel(fmc, __cpu_to_be32(*p), ram + count);
out:
release_firmware(fw);
return ret;
}
/**
* Program FPGA Gateware including NIC with or without DIO support.
*
* @param fmc FMC device
* @param has_dio Include DIO support (=1) or only NIC.
*
* @return 0 if success and a negative error code otherwise
*/
int spec_gw_program(struct fmc_device *fmc, int has_dio)
{
int ret = 0;
struct spec_dev *spec = fmc->carrier_data;
struct device *dev = &spec->pdev->dev;
signed long ram, syscon;
unsigned long ramsize;
char *filename = NIC_LM32_FW_NAME;
unsigned long j;
/* First, free SDB tree */
fmc_free_sdb_tree(fmc);
/* Program FPGA bitstream */
if(has_dio) {
spec->sdb_entry = SDB_NIC_DIO_ENTRY;
ret = spec_load_fpga_file(spec,DIO_GW_NAME);
} else {
spec->sdb_entry = SDB_NIC_ENTRY;
ret = spec_load_fpga_file(spec,NIC_GW_NAME);
}
if(ret)
goto out;
/* Load SDB information */
ret = spec_sdb_load(fmc);
if(ret)
goto out;
/* Write LM32 firmware for WR-NIC design */
ram = fmc_find_sdb_device(fmc->sdb, SDB_CERN_VENDOR, SDB_RAM_PID, &ramsize);
syscon = spec->syscon_addr;
j = jiffies + HZ/2;
fmc_writel(fmc, SYSCON_RESET_ON, syscon);
while ( !(fmc_readl(fmc, syscon) & (1 << 28)) )
if (time_after(jiffies, j))
break;
if (time_after(jiffies, j)) {
dev_err(dev, "can't reset LM32\n");
fmc_writel(fmc, SYSCON_RESET_OFF, syscon);
goto out;
}
ret = spec_lm32_fw_load(fmc, filename, ram, ramsize);
fmc_writel(fmc, SYSCON_RESET_OFF, syscon);
if (ret)
goto out; /* message already reported */
if (fmc_readl(fmc, ram) != RAM_MAGIC)
dev_warn(dev, "possible failure in wrc load\n");
else
dev_info(dev, "WRC program reloaded from \"%s\"\n",
filename);
return 0;
out:
return ret;
}
......@@ -27,8 +27,14 @@
#define SPEC_NAME_LEN 10
#define GNINT_STAT_GPIO BIT(15)
#define GNINT_STAT_SW0 BIT(2)
#define GNINT_STAT_SW1 BIT(3)
#define GNINT_STAT_SW_ALL (GNINT_STAT_SW0 | GNINT_STAT_SW1)
/* Our device structure */
struct spec_dev {
struct irq_domain *gpio_domain;
struct pci_dev *pdev;
struct resource *area[3]; /* bar 0, 2, 4 */
void __iomem *remap[3]; /* ioremap of bar 0, 2, 4 */
......@@ -42,12 +48,16 @@ struct spec_dev {
char name[SPEC_NAME_LEN];
unsigned int sdb_entry;
unsigned long syscon_addr;
unsigned long syscon_size;
};
#define SPEC_FLAG_FAKE_EEPROM 0x00000001
#define SPEC_FLAG_IRQS_REQUESTED 0x00000002
#define SPEC_FLAG_FMC_REGISTERED 0x00000004
#define GN4124_GPIO_IRQ_MAX 16
/* Registers for GN4124 access */
enum {
/* page 106 */
......@@ -136,6 +146,10 @@ extern int spec_use_msi;
extern int spec_fmc_create(struct spec_dev *spec, struct fmc_gateware *gw);
extern void spec_fmc_destroy(struct spec_dev *spec);
/* Functions in spec-irq.c, used by spec-fmc.c */
extern int spec_irq_init(struct spec_dev *spec);
extern void spec_irq_exit(struct spec_dev *spec);
/* Functions in spec-i2c.c, used by spec-fmc.c */
extern int spec_i2c_init(struct fmc_device *fmc);
extern void spec_i2c_exit(struct fmc_device *fmc);
......@@ -152,5 +166,10 @@ extern int spec_eeprom_write(struct fmc_device *fmc, uint32_t offset,
extern int spec_gpio_init(struct fmc_device *fmc);
extern void spec_gpio_exit(struct fmc_device *fmc);
/* Functions in spec-sdb-scan.c */
extern int spec_sdb_fpga_dev_register_all(struct fmc_device *fmc);
extern void spec_sdb_fpga_dev_release_all(struct fmc_device *fmc);
extern int spec_sdb_load(struct fmc_device *fmc);
extern int spec_gw_program(struct fmc_device *fmc, int has_dio);
#endif /* __SPEC_H__ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment