Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6) #include <linux/of_platform.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) #include <asm/oplib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <asm/prom.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <asm/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <asm/upa.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include "prom.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #ifdef CONFIG_PCI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) /* PSYCHO interrupt mapping support. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #define PSYCHO_IMAP_A_SLOT0	0x0c00UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #define PSYCHO_IMAP_B_SLOT0	0x0c20UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) static unsigned long psycho_pcislot_imap_offset(unsigned long ino)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) 	unsigned int bus =  (ino & 0x10) >> 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 	unsigned int slot = (ino & 0x0c) >> 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 	if (bus == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) 		return PSYCHO_IMAP_A_SLOT0 + (slot * 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 		return PSYCHO_IMAP_B_SLOT0 + (slot * 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) #define PSYCHO_OBIO_IMAP_BASE	0x1000UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) #define PSYCHO_ONBOARD_IRQ_BASE		0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) #define psycho_onboard_imap_offset(__ino) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 	(PSYCHO_OBIO_IMAP_BASE + (((__ino) & 0x1f) << 3))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) #define PSYCHO_ICLR_A_SLOT0	0x1400UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) #define PSYCHO_ICLR_SCSI	0x1800UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) #define psycho_iclr_offset(ino)					      \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 	((ino & 0x20) ? (PSYCHO_ICLR_SCSI + (((ino) & 0x1f) << 3)) :  \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 			(PSYCHO_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) static unsigned int psycho_irq_build(struct device_node *dp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 				     unsigned int ino,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 				     void *_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 	unsigned long controller_regs = (unsigned long) _data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 	unsigned long imap, iclr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 	unsigned long imap_off, iclr_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	int inofixup = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	ino &= 0x3f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	if (ino < PSYCHO_ONBOARD_IRQ_BASE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 		/* PCI slot */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 		imap_off = psycho_pcislot_imap_offset(ino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 		/* Onboard device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 		imap_off = psycho_onboard_imap_offset(ino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 	/* Now build the IRQ bucket. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 	imap = controller_regs + imap_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 	iclr_off = psycho_iclr_offset(ino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 	iclr = controller_regs + iclr_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 	if ((ino & 0x20) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 		inofixup = ino & 0x03;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	return build_irq(inofixup, iclr, imap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) static void __init psycho_irq_trans_init(struct device_node *dp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	const struct linux_prom64_registers *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 	dp->irq_trans->irq_build = psycho_irq_build;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 	regs = of_get_property(dp, "reg", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	dp->irq_trans->data = (void *) regs[2].phys_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) #define sabre_read(__reg) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) ({	u64 __ret; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 	__asm__ __volatile__("ldxa [%1] %2, %0" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 			     : "=r" (__ret) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 			     : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 			     : "memory"); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	__ret; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) })
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) struct sabre_irq_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	unsigned long controller_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 	unsigned int pci_first_busno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) #define SABRE_CONFIGSPACE	0x001000000UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) #define SABRE_WRSYNC		0x1c20UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) #define SABRE_CONFIG_BASE(CONFIG_SPACE)	\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	(CONFIG_SPACE | (1UL << 24))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) #define SABRE_CONFIG_ENCODE(BUS, DEVFN, REG)	\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	(((unsigned long)(BUS)   << 16) |	\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	 ((unsigned long)(DEVFN) << 8)  |	\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	 ((unsigned long)(REG)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /* When a device lives behind a bridge deeper in the PCI bus topology
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)  * than APB, a special sequence must run to make sure all pending DMA
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)  * transfers at the time of IRQ delivery are visible in the coherency
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)  * domain by the cpu.  This sequence is to perform a read on the far
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)  * side of the non-APB bridge, then perform a read of Sabre's DMA
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)  * write-sync register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) static void sabre_wsync_handler(unsigned int ino, void *_arg1, void *_arg2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 	unsigned int phys_hi = (unsigned int) (unsigned long) _arg1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	struct sabre_irq_data *irq_data = _arg2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 	unsigned long controller_regs = irq_data->controller_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	unsigned long sync_reg = controller_regs + SABRE_WRSYNC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 	unsigned long config_space = controller_regs + SABRE_CONFIGSPACE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	unsigned int bus, devfn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 	u16 _unused;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	config_space = SABRE_CONFIG_BASE(config_space);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 	bus = (phys_hi >> 16) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 	devfn = (phys_hi >> 8) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 	config_space |= SABRE_CONFIG_ENCODE(bus, devfn, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	__asm__ __volatile__("membar #Sync\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 			     "lduha [%1] %2, %0\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 			     "membar #Sync"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 			     : "=r" (_unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 			     : "r" ((u16 *) config_space),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 			       "i" (ASI_PHYS_BYPASS_EC_E_L)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 			     : "memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	sabre_read(sync_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) #define SABRE_IMAP_A_SLOT0	0x0c00UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) #define SABRE_IMAP_B_SLOT0	0x0c20UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) #define SABRE_ICLR_A_SLOT0	0x1400UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) #define SABRE_ICLR_B_SLOT0	0x1480UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) #define SABRE_ICLR_SCSI		0x1800UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) #define SABRE_ICLR_ETH		0x1808UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) #define SABRE_ICLR_BPP		0x1810UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) #define SABRE_ICLR_AU_REC	0x1818UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) #define SABRE_ICLR_AU_PLAY	0x1820UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) #define SABRE_ICLR_PFAIL	0x1828UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) #define SABRE_ICLR_KMS		0x1830UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) #define SABRE_ICLR_FLPY		0x1838UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) #define SABRE_ICLR_SHW		0x1840UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) #define SABRE_ICLR_KBD		0x1848UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) #define SABRE_ICLR_MS		0x1850UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) #define SABRE_ICLR_SER		0x1858UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) #define SABRE_ICLR_UE		0x1870UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) #define SABRE_ICLR_CE		0x1878UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) #define SABRE_ICLR_PCIERR	0x1880UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) static unsigned long sabre_pcislot_imap_offset(unsigned long ino)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	unsigned int bus =  (ino & 0x10) >> 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 	unsigned int slot = (ino & 0x0c) >> 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	if (bus == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 		return SABRE_IMAP_A_SLOT0 + (slot * 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 		return SABRE_IMAP_B_SLOT0 + (slot * 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) #define SABRE_OBIO_IMAP_BASE	0x1000UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) #define SABRE_ONBOARD_IRQ_BASE	0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) #define sabre_onboard_imap_offset(__ino) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 	(SABRE_OBIO_IMAP_BASE + (((__ino) & 0x1f) << 3))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) #define sabre_iclr_offset(ino)					      \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 	((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) :  \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 			(SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) static int sabre_device_needs_wsync(struct device_node *dp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 	struct device_node *parent = dp->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 	const char *parent_model, *parent_compat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 	/* This traversal up towards the root is meant to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 	 * handle two cases:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 	 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 	 * 1) non-PCI bus sitting under PCI, such as 'ebus'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	 * 2) the PCI controller interrupts themselves, which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 	 *    will use the sabre_irq_build but do not need
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	 *    the DMA synchronization handling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 	while (parent) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 		if (of_node_is_type(parent, "pci"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 		parent = parent->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 	if (!parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 	parent_model = of_get_property(parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 				       "model", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 	if (parent_model &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 	    (!strcmp(parent_model, "SUNW,sabre") ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 	     !strcmp(parent_model, "SUNW,simba")))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 	parent_compat = of_get_property(parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 					"compatible", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 	if (parent_compat &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 	    (!strcmp(parent_compat, "pci108e,a000") ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 	     !strcmp(parent_compat, "pci108e,a001")))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 	return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) static unsigned int sabre_irq_build(struct device_node *dp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 				    unsigned int ino,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 				    void *_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 	struct sabre_irq_data *irq_data = _data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 	unsigned long controller_regs = irq_data->controller_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 	const struct linux_prom_pci_registers *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 	unsigned long imap, iclr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 	unsigned long imap_off, iclr_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 	int inofixup = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 	int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 	ino &= 0x3f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 	if (ino < SABRE_ONBOARD_IRQ_BASE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 		/* PCI slot */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 		imap_off = sabre_pcislot_imap_offset(ino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 		/* onboard device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 		imap_off = sabre_onboard_imap_offset(ino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 	/* Now build the IRQ bucket. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 	imap = controller_regs + imap_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 	iclr_off = sabre_iclr_offset(ino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 	iclr = controller_regs + iclr_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 	if ((ino & 0x20) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 		inofixup = ino & 0x03;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 	irq = build_irq(inofixup, iclr, imap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 	/* If the parent device is a PCI<->PCI bridge other than
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 	 * APB, we have to install a pre-handler to ensure that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 	 * all pending DMA is drained before the interrupt handler
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 	 * is run.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	regs = of_get_property(dp, "reg", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 	if (regs && sabre_device_needs_wsync(dp)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 		irq_install_pre_handler(irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 					sabre_wsync_handler,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 					(void *) (long) regs->phys_hi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 					(void *) irq_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 	return irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) static void __init sabre_irq_trans_init(struct device_node *dp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 	const struct linux_prom64_registers *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 	struct sabre_irq_data *irq_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 	const u32 *busrange;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 	dp->irq_trans->irq_build = sabre_irq_build;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 	irq_data = prom_early_alloc(sizeof(struct sabre_irq_data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 	regs = of_get_property(dp, "reg", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 	irq_data->controller_regs = regs[0].phys_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 	busrange = of_get_property(dp, "bus-range", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 	irq_data->pci_first_busno = busrange[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 	dp->irq_trans->data = irq_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) /* SCHIZO interrupt mapping support.  Unlike Psycho, for this controller the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)  * imap/iclr registers are per-PBM.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) #define SCHIZO_IMAP_BASE	0x1000UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) #define SCHIZO_ICLR_BASE	0x1400UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) static unsigned long schizo_imap_offset(unsigned long ino)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 	return SCHIZO_IMAP_BASE + (ino * 8UL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) static unsigned long schizo_iclr_offset(unsigned long ino)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 	return SCHIZO_ICLR_BASE + (ino * 8UL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) static unsigned long schizo_ino_to_iclr(unsigned long pbm_regs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 					unsigned int ino)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 	return pbm_regs + schizo_iclr_offset(ino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) static unsigned long schizo_ino_to_imap(unsigned long pbm_regs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 					unsigned int ino)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 	return pbm_regs + schizo_imap_offset(ino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) #define schizo_read(__reg) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) ({	u64 __ret; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 	__asm__ __volatile__("ldxa [%1] %2, %0" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 			     : "=r" (__ret) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 			     : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 			     : "memory"); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 	__ret; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) })
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) #define schizo_write(__reg, __val) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 	__asm__ __volatile__("stxa %0, [%1] %2" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 			     : /* no outputs */ \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 			     : "r" (__val), "r" (__reg), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 			       "i" (ASI_PHYS_BYPASS_EC_E) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 			     : "memory")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) static void tomatillo_wsync_handler(unsigned int ino, void *_arg1, void *_arg2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 	unsigned long sync_reg = (unsigned long) _arg2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 	u64 mask = 1UL << (ino & IMAP_INO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 	u64 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 	int limit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 	schizo_write(sync_reg, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 	limit = 100000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 	val = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 	while (--limit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 		val = schizo_read(sync_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 		if (!(val & mask))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 	if (limit <= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 		printk("tomatillo_wsync_handler: DMA won't sync [%llx:%llx]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 		       val, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 	if (_arg1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 		static unsigned char cacheline[64]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 			__attribute__ ((aligned (64)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 		__asm__ __volatile__("rd %%fprs, %0\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 				     "or %0, %4, %1\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 				     "wr %1, 0x0, %%fprs\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 				     "stda %%f0, [%5] %6\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 				     "wr %0, 0x0, %%fprs\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 				     "membar #Sync"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 				     : "=&r" (mask), "=&r" (val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 				     : "0" (mask), "1" (val),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 				     "i" (FPRS_FEF), "r" (&cacheline[0]),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 				     "i" (ASI_BLK_COMMIT_P));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) struct schizo_irq_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 	unsigned long pbm_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 	unsigned long sync_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 	u32 portid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 	int chip_version;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) static unsigned int schizo_irq_build(struct device_node *dp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 				     unsigned int ino,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 				     void *_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 	struct schizo_irq_data *irq_data = _data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 	unsigned long pbm_regs = irq_data->pbm_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 	unsigned long imap, iclr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 	int ign_fixup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 	int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 	int is_tomatillo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 	ino &= 0x3f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 	/* Now build the IRQ bucket. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 	imap = schizo_ino_to_imap(pbm_regs, ino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 	iclr = schizo_ino_to_iclr(pbm_regs, ino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 	/* On Schizo, no inofixup occurs.  This is because each
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 	 * INO has it's own IMAP register.  On Psycho and Sabre
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 	 * there is only one IMAP register for each PCI slot even
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 	 * though four different INOs can be generated by each
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 	 * PCI slot.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 	 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 	 * But, for JBUS variants (essentially, Tomatillo), we have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 	 * to fixup the lowest bit of the interrupt group number.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 	ign_fixup = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 	is_tomatillo = (irq_data->sync_reg != 0UL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 	if (is_tomatillo) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 		if (irq_data->portid & 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 			ign_fixup = (1 << 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 	irq = build_irq(ign_fixup, iclr, imap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 	if (is_tomatillo) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 		irq_install_pre_handler(irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 					tomatillo_wsync_handler,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 					((irq_data->chip_version <= 4) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 					 (void *) 1 : (void *) 0),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 					(void *) irq_data->sync_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 	return irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) static void __init __schizo_irq_trans_init(struct device_node *dp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 					   int is_tomatillo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) 	const struct linux_prom64_registers *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 	struct schizo_irq_data *irq_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 	dp->irq_trans->irq_build = schizo_irq_build;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 	irq_data = prom_early_alloc(sizeof(struct schizo_irq_data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 	regs = of_get_property(dp, "reg", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) 	dp->irq_trans->data = irq_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) 	irq_data->pbm_regs = regs[0].phys_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) 	if (is_tomatillo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) 		irq_data->sync_reg = regs[3].phys_addr + 0x1a18UL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 		irq_data->sync_reg = 0UL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) 	irq_data->portid = of_getintprop_default(dp, "portid", 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 	irq_data->chip_version = of_getintprop_default(dp, "version#", 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) static void __init schizo_irq_trans_init(struct device_node *dp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 	__schizo_irq_trans_init(dp, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) static void __init tomatillo_irq_trans_init(struct device_node *dp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 	__schizo_irq_trans_init(dp, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) static unsigned int pci_sun4v_irq_build(struct device_node *dp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) 					unsigned int devino,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 					void *_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) 	u32 devhandle = (u32) (unsigned long) _data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) 	return sun4v_build_irq(devhandle, devino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) static void __init pci_sun4v_irq_trans_init(struct device_node *dp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) 	const struct linux_prom64_registers *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 	dp->irq_trans->irq_build = pci_sun4v_irq_build;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 	regs = of_get_property(dp, "reg", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 	dp->irq_trans->data = (void *) (unsigned long)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 		((regs->phys_addr >> 32UL) & 0x0fffffff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) struct fire_irq_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 	unsigned long pbm_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) 	u32 portid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) #define FIRE_IMAP_BASE	0x001000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) #define FIRE_ICLR_BASE	0x001400
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) static unsigned long fire_imap_offset(unsigned long ino)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) 	return FIRE_IMAP_BASE + (ino * 8UL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) static unsigned long fire_iclr_offset(unsigned long ino)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) 	return FIRE_ICLR_BASE + (ino * 8UL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) static unsigned long fire_ino_to_iclr(unsigned long pbm_regs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) 					    unsigned int ino)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) 	return pbm_regs + fire_iclr_offset(ino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) static unsigned long fire_ino_to_imap(unsigned long pbm_regs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) 					    unsigned int ino)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) 	return pbm_regs + fire_imap_offset(ino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) static unsigned int fire_irq_build(struct device_node *dp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) 					 unsigned int ino,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) 					 void *_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) 	struct fire_irq_data *irq_data = _data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) 	unsigned long pbm_regs = irq_data->pbm_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) 	unsigned long imap, iclr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) 	unsigned long int_ctrlr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) 	ino &= 0x3f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) 	/* Now build the IRQ bucket. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) 	imap = fire_ino_to_imap(pbm_regs, ino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) 	iclr = fire_ino_to_iclr(pbm_regs, ino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) 	/* Set the interrupt controller number.  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) 	int_ctrlr = 1 << 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) 	upa_writeq(int_ctrlr, imap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) 	/* The interrupt map registers do not have an INO field
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) 	 * like other chips do.  They return zero in the INO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) 	 * field, and the interrupt controller number is controlled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) 	 * in bits 6 to 9.  So in order for build_irq() to get
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) 	 * the INO right we pass it in as part of the fixup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) 	 * which will get added to the map register zero value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) 	 * read by build_irq().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) 	ino |= (irq_data->portid << 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) 	ino -= int_ctrlr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) 	return build_irq(ino, iclr, imap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) static void __init fire_irq_trans_init(struct device_node *dp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) 	const struct linux_prom64_registers *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) 	struct fire_irq_data *irq_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) 	dp->irq_trans->irq_build = fire_irq_build;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) 	irq_data = prom_early_alloc(sizeof(struct fire_irq_data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) 	regs = of_get_property(dp, "reg", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) 	dp->irq_trans->data = irq_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) 	irq_data->pbm_regs = regs[0].phys_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) 	irq_data->portid = of_getintprop_default(dp, "portid", 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) #endif /* CONFIG_PCI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) #ifdef CONFIG_SBUS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) /* INO number to IMAP register offset for SYSIO external IRQ's.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)  * This should conform to both Sunfire/Wildfire server and Fusion
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)  * desktop designs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) #define SYSIO_IMAP_SLOT0	0x2c00UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) #define SYSIO_IMAP_SLOT1	0x2c08UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) #define SYSIO_IMAP_SLOT2	0x2c10UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) #define SYSIO_IMAP_SLOT3	0x2c18UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) #define SYSIO_IMAP_SCSI		0x3000UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) #define SYSIO_IMAP_ETH		0x3008UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) #define SYSIO_IMAP_BPP		0x3010UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) #define SYSIO_IMAP_AUDIO	0x3018UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) #define SYSIO_IMAP_PFAIL	0x3020UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) #define SYSIO_IMAP_KMS		0x3028UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) #define SYSIO_IMAP_FLPY		0x3030UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) #define SYSIO_IMAP_SHW		0x3038UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) #define SYSIO_IMAP_KBD		0x3040UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) #define SYSIO_IMAP_MS		0x3048UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) #define SYSIO_IMAP_SER		0x3050UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) #define SYSIO_IMAP_TIM0		0x3060UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) #define SYSIO_IMAP_TIM1		0x3068UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) #define SYSIO_IMAP_UE		0x3070UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) #define SYSIO_IMAP_CE		0x3078UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) #define SYSIO_IMAP_SBERR	0x3080UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) #define SYSIO_IMAP_PMGMT	0x3088UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) #define SYSIO_IMAP_GFX		0x3090UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) #define SYSIO_IMAP_EUPA		0x3098UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) #define bogon     ((unsigned long) -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) static unsigned long sysio_irq_offsets[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) 	/* SBUS Slot 0 --> 3, level 1 --> 7 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) 	SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) 	SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0, SYSIO_IMAP_SLOT0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) 	SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) 	SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1, SYSIO_IMAP_SLOT1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) 	SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) 	SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2, SYSIO_IMAP_SLOT2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) 	SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) 	SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3, SYSIO_IMAP_SLOT3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) 	/* Onboard devices (not relevant/used on SunFire). */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) 	SYSIO_IMAP_SCSI,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) 	SYSIO_IMAP_ETH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) 	SYSIO_IMAP_BPP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) 	bogon,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) 	SYSIO_IMAP_AUDIO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) 	SYSIO_IMAP_PFAIL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) 	bogon,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) 	bogon,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) 	SYSIO_IMAP_KMS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) 	SYSIO_IMAP_FLPY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) 	SYSIO_IMAP_SHW,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) 	SYSIO_IMAP_KBD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) 	SYSIO_IMAP_MS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) 	SYSIO_IMAP_SER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) 	bogon,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) 	bogon,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) 	SYSIO_IMAP_TIM0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) 	SYSIO_IMAP_TIM1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) 	bogon,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) 	bogon,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) 	SYSIO_IMAP_UE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) 	SYSIO_IMAP_CE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) 	SYSIO_IMAP_SBERR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) 	SYSIO_IMAP_PMGMT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) 	SYSIO_IMAP_GFX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) 	SYSIO_IMAP_EUPA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) #undef bogon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) #define NUM_SYSIO_OFFSETS ARRAY_SIZE(sysio_irq_offsets)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) /* Convert Interrupt Mapping register pointer to associated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635)  * Interrupt Clear register pointer, SYSIO specific version.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) #define SYSIO_ICLR_UNUSED0	0x3400UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) #define SYSIO_ICLR_SLOT0	0x3408UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) #define SYSIO_ICLR_SLOT1	0x3448UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) #define SYSIO_ICLR_SLOT2	0x3488UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) #define SYSIO_ICLR_SLOT3	0x34c8UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) static unsigned long sysio_imap_to_iclr(unsigned long imap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) 	unsigned long diff = SYSIO_ICLR_UNUSED0 - SYSIO_IMAP_SLOT0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) 	return imap + diff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) static unsigned int sbus_of_build_irq(struct device_node *dp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) 				      unsigned int ino,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) 				      void *_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) 	unsigned long reg_base = (unsigned long) _data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) 	const struct linux_prom_registers *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) 	unsigned long imap, iclr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) 	int sbus_slot = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) 	int sbus_level = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) 	ino &= 0x3f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) 	regs = of_get_property(dp, "reg", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) 	if (regs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) 		sbus_slot = regs->which_io;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) 	if (ino < 0x20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) 		ino += (sbus_slot * 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) 	imap = sysio_irq_offsets[ino];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) 	if (imap == ((unsigned long)-1)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) 		prom_printf("get_irq_translations: Bad SYSIO INO[%x]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) 			    ino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) 		prom_halt();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) 	imap += reg_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) 	/* SYSIO inconsistency.  For external SLOTS, we have to select
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) 	 * the right ICLR register based upon the lower SBUS irq level
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) 	 * bits.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) 	if (ino >= 0x20) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) 		iclr = sysio_imap_to_iclr(imap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) 		sbus_level = ino & 0x7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) 		switch(sbus_slot) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) 		case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) 			iclr = reg_base + SYSIO_ICLR_SLOT0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) 		case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) 			iclr = reg_base + SYSIO_ICLR_SLOT1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) 		case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) 			iclr = reg_base + SYSIO_ICLR_SLOT2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) 		default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) 		case 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) 			iclr = reg_base + SYSIO_ICLR_SLOT3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) 		iclr += ((unsigned long)sbus_level - 1UL) * 8UL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) 	return build_irq(sbus_level, iclr, imap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) static void __init sbus_irq_trans_init(struct device_node *dp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) 	const struct linux_prom64_registers *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) 	dp->irq_trans->irq_build = sbus_of_build_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) 	regs = of_get_property(dp, "reg", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) 	dp->irq_trans->data = (void *) (unsigned long) regs->phys_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) #endif /* CONFIG_SBUS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) static unsigned int central_build_irq(struct device_node *dp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) 				      unsigned int ino,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) 				      void *_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) 	struct device_node *central_dp = _data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) 	struct platform_device *central_op = of_find_device_by_node(central_dp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) 	struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) 	unsigned long imap, iclr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) 	u32 tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) 	if (of_node_name_eq(dp, "eeprom")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) 		res = &central_op->resource[5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) 	} else if (of_node_name_eq(dp, "zs")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) 		res = &central_op->resource[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) 	} else if (of_node_name_eq(dp, "clock-board")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) 		res = &central_op->resource[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) 		return ino;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) 	imap = res->start + 0x00UL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) 	iclr = res->start + 0x10UL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) 	/* Set the INO state to idle, and disable.  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) 	upa_writel(0, iclr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) 	upa_readl(iclr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) 	tmp = upa_readl(imap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) 	tmp &= ~0x80000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) 	upa_writel(tmp, imap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) 	return build_irq(0, iclr, imap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) static void __init central_irq_trans_init(struct device_node *dp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) 	dp->irq_trans->irq_build = central_build_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) 	dp->irq_trans->data = dp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) struct irq_trans {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) 	const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) 	void (*init)(struct device_node *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) #ifdef CONFIG_PCI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) static struct irq_trans __initdata pci_irq_trans_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) 	{ "SUNW,sabre", sabre_irq_trans_init },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) 	{ "pci108e,a000", sabre_irq_trans_init },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) 	{ "pci108e,a001", sabre_irq_trans_init },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) 	{ "SUNW,psycho", psycho_irq_trans_init },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) 	{ "pci108e,8000", psycho_irq_trans_init },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) 	{ "SUNW,schizo", schizo_irq_trans_init },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) 	{ "pci108e,8001", schizo_irq_trans_init },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) 	{ "SUNW,schizo+", schizo_irq_trans_init },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) 	{ "pci108e,8002", schizo_irq_trans_init },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) 	{ "SUNW,tomatillo", tomatillo_irq_trans_init },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) 	{ "pci108e,a801", tomatillo_irq_trans_init },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) 	{ "SUNW,sun4v-pci", pci_sun4v_irq_trans_init },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) 	{ "pciex108e,80f0", fire_irq_trans_init },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) static unsigned int sun4v_vdev_irq_build(struct device_node *dp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) 					 unsigned int devino,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) 					 void *_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) 	u32 devhandle = (u32) (unsigned long) _data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) 	return sun4v_build_irq(devhandle, devino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) static void __init sun4v_vdev_irq_trans_init(struct device_node *dp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) 	const struct linux_prom64_registers *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) 	dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) 	dp->irq_trans->irq_build = sun4v_vdev_irq_build;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) 	regs = of_get_property(dp, "reg", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) 	dp->irq_trans->data = (void *) (unsigned long)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) 		((regs->phys_addr >> 32UL) & 0x0fffffff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) void __init irq_trans_init(struct device_node *dp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) #ifdef CONFIG_PCI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) 	const char *model;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) #ifdef CONFIG_PCI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) 	model = of_get_property(dp, "model", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) 	if (!model)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) 		model = of_get_property(dp, "compatible", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) 	if (model) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) 		for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) 			struct irq_trans *t = &pci_irq_trans_table[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) 			if (!strcmp(model, t->name)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) 				t->init(dp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) 				return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) #ifdef CONFIG_SBUS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) 	if (of_node_name_eq(dp, "sbus") ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) 	    of_node_name_eq(dp, "sbi")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) 		sbus_irq_trans_init(dp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) 	if (of_node_name_eq(dp, "fhc") &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) 	    of_node_name_eq(dp->parent, "central")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) 		central_irq_trans_init(dp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) 	if (of_node_name_eq(dp, "virtual-devices") ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) 	    of_node_name_eq(dp, "niu")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) 		sun4v_vdev_irq_trans_init(dp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) }