#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: iyonix_pci.c,v 1.10 2019/01/23 22:13:01 macallan Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <machine/autoconf.h>
#include <sys/bus.h>
#include <iyonix/iyonix/iyonixreg.h>
#include <iyonix/iyonix/iyonixvar.h>
#include <arm/xscale/i80321reg.h>
#include <arm/xscale/i80321var.h>
#include <dev/pci/pcidevs.h>
#include <dev/pci/ppbreg.h>
#include <sys/extent.h>
#include <dev/pci/pciconf.h>
int iyonix_pci_intr_map(const struct pci_attach_args *,
pci_intr_handle_t *);
const char *iyonix_pci_intr_string(void *, pci_intr_handle_t, char *, size_t);
const struct evcnt *iyonix_pci_intr_evcnt(void *, pci_intr_handle_t);
void *iyonix_pci_intr_establish(void *, pci_intr_handle_t,
int, int (*func)(void *), void *, const char *);
void iyonix_pci_intr_disestablish(void *, void *);
void pci_conf_write_byte(pci_chipset_tag_t, pcitag_t, int, int);
int pci_conf_read_byte(pci_chipset_tag_t, pcitag_t, int);
int iyonix_pci_conf_hook(void *, int, int, int, pcireg_t);
void
iyonix_pci_init(pci_chipset_tag_t pc, void *cookie)
{
pc->pc_intr_v = cookie;
pc->pc_intr_map = iyonix_pci_intr_map;
pc->pc_intr_string = iyonix_pci_intr_string;
pc->pc_intr_evcnt = iyonix_pci_intr_evcnt;
pc->pc_intr_establish = iyonix_pci_intr_establish;
pc->pc_intr_disestablish = iyonix_pci_intr_disestablish;
pc->pc_conf_hook = iyonix_pci_conf_hook;
}
int
iyonix_pci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp)
{
struct i80321_softc *sc = pa->pa_pc->pc_intr_v;
int b, d, f;
uint32_t busno;
busno = bus_space_read_4(sc->sc_st, sc->sc_atu_sh, ATU_PCIXSR);
busno = PCIXSR_BUSNO(busno);
if (busno == 0xff)
busno = 0;
pci_decompose_tag(pa->pa_pc, pa->pa_intrtag, &b, &d, &f);
if (b != busno)
goto no_mapping;
if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ALI) {
switch (PCI_PRODUCT(pa->pa_id)) {
case PCI_PRODUCT_ALI_M1543:
case PCI_PRODUCT_ALI_M5229:
case PCI_PRODUCT_ALI_M5237:
case PCI_PRODUCT_ALI_M5257:
case PCI_PRODUCT_ALI_M5451:
case PCI_PRODUCT_ALI_M7101:
*ihp = ICU_INT_XINT(1);
return (0);
}
}
*ihp = ICU_INT_XINT((d + pa->pa_intrpin - 1) % 4);
return 0;
no_mapping:
printf("iyonix_pci_intr_map: no mapping for %d/%d/%d\n",
pa->pa_bus, pa->pa_device, pa->pa_function);
return (1);
}
const char *
iyonix_pci_intr_string(void *v, pci_intr_handle_t ih, char *buf, size_t len)
{
strlcpy(buf, i80321_irqnames[ih], len);
return buf;
}
const struct evcnt *
iyonix_pci_intr_evcnt(void *v, pci_intr_handle_t ih)
{
return (NULL);
}
void *
iyonix_pci_intr_establish(void *v, pci_intr_handle_t ih, int ipl,
int (*func)(void *), void *arg, const char *xname)
{
return (i80321_intr_establish(ih, ipl, func, arg));
}
void
iyonix_pci_intr_disestablish(void *v, void *cookie)
{
i80321_intr_disestablish(cookie);
}
void
pci_conf_write_byte(pci_chipset_tag_t pc, pcitag_t tag, int addr, int value)
{
int temp;
temp = pci_conf_read(pc, tag, addr&~3);
temp = temp & ~(0xff << ((addr%4) * 8));
temp = temp | (value << ((addr%4) * 8));
pci_conf_write(pc, tag, addr&~3, temp);
}
int
pci_conf_read_byte(pci_chipset_tag_t pc, pcitag_t tag, int addr)
{
int temp;
temp = pci_conf_read(pc, tag, addr&~3);
temp = temp >> ((addr%4) * 8);
temp = temp & 0xff;
return temp;
}
int
iyonix_pci_conf_hook(void *v, int bus, int dev, int func, pcireg_t id)
{
if (PCI_VENDOR(id) == PCI_VENDOR_ALI &&
PCI_PRODUCT(id) == PCI_PRODUCT_ALI_M1543)
{
pcitag_t tag;
int status;
pci_chipset_tag_t pc = (pci_chipset_tag_t) v;
tag = pci_make_tag(pc, bus, dev, func);
pci_conf_write_byte(pc, tag, 0x53, 0x40);
pci_conf_write_byte(pc, tag, 0x52, 0x00);
status = pci_conf_read_byte(pc, tag, 0x7e);
pci_conf_write_byte(pc, tag, 0x7e, status & ~0x80);
pci_conf_write_byte(pc, tag, 0x77, 1 << 6);
pci_conf_write_byte(pc, tag, 0x78, 1 << 7);
}
return (PCI_CONF_DEFAULT);
}