1*ff4a7481SKuninori Morimoto // SPDX-License-Identifier: GPL-2.0
2959f85f8SPaul Mundt /*
3959f85f8SPaul Mundt * Generic SH-4 / SH-4A PCIC operations (SH7751, SH7780).
4959f85f8SPaul Mundt *
57e4ba0d7SPaul Mundt * Copyright (C) 2002 - 2009 Paul Mundt
6959f85f8SPaul Mundt */
7959f85f8SPaul Mundt #include <linux/pci.h>
87e4ba0d7SPaul Mundt #include <linux/io.h>
939a90865SPaul Mundt #include <linux/spinlock.h>
10959f85f8SPaul Mundt #include <asm/addrspace.h>
11959f85f8SPaul Mundt #include "pci-sh4.h"
12959f85f8SPaul Mundt
13959f85f8SPaul Mundt /*
14959f85f8SPaul Mundt * Direct access to PCI hardware...
15959f85f8SPaul Mundt */
16959f85f8SPaul Mundt #define CONFIG_CMD(bus, devfn, where) \
17ef407beeSPaul Mundt (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3))
18959f85f8SPaul Mundt
19959f85f8SPaul Mundt /*
20959f85f8SPaul Mundt * Functions for accessing PCI configuration space with type 1 accesses
21959f85f8SPaul Mundt */
sh4_pci_read(struct pci_bus * bus,unsigned int devfn,int where,int size,u32 * val)22959f85f8SPaul Mundt static int sh4_pci_read(struct pci_bus *bus, unsigned int devfn,
23959f85f8SPaul Mundt int where, int size, u32 *val)
24959f85f8SPaul Mundt {
25b6706ef1SMagnus Damm struct pci_channel *chan = bus->sysdata;
26959f85f8SPaul Mundt unsigned long flags;
27959f85f8SPaul Mundt u32 data;
28959f85f8SPaul Mundt
29959f85f8SPaul Mundt /*
30959f85f8SPaul Mundt * PCIPDR may only be accessed as 32 bit words,
31959f85f8SPaul Mundt * so we must do byte alignment by hand
32959f85f8SPaul Mundt */
3339a90865SPaul Mundt raw_spin_lock_irqsave(&pci_config_lock, flags);
34b6706ef1SMagnus Damm pci_write_reg(chan, CONFIG_CMD(bus, devfn, where), SH4_PCIPAR);
35b6706ef1SMagnus Damm data = pci_read_reg(chan, SH4_PCIPDR);
3639a90865SPaul Mundt raw_spin_unlock_irqrestore(&pci_config_lock, flags);
37959f85f8SPaul Mundt
38959f85f8SPaul Mundt switch (size) {
39959f85f8SPaul Mundt case 1:
40959f85f8SPaul Mundt *val = (data >> ((where & 3) << 3)) & 0xff;
41959f85f8SPaul Mundt break;
42959f85f8SPaul Mundt case 2:
43959f85f8SPaul Mundt *val = (data >> ((where & 2) << 3)) & 0xffff;
44959f85f8SPaul Mundt break;
45959f85f8SPaul Mundt case 4:
46959f85f8SPaul Mundt *val = data;
47959f85f8SPaul Mundt break;
48959f85f8SPaul Mundt default:
49959f85f8SPaul Mundt return PCIBIOS_FUNC_NOT_SUPPORTED;
50959f85f8SPaul Mundt }
51959f85f8SPaul Mundt
52959f85f8SPaul Mundt return PCIBIOS_SUCCESSFUL;
53959f85f8SPaul Mundt }
54959f85f8SPaul Mundt
55959f85f8SPaul Mundt /*
56959f85f8SPaul Mundt * Since SH4 only does 32bit access we'll have to do a read,
57959f85f8SPaul Mundt * mask,write operation.
58959f85f8SPaul Mundt * We'll allow an odd byte offset, though it should be illegal.
59959f85f8SPaul Mundt */
sh4_pci_write(struct pci_bus * bus,unsigned int devfn,int where,int size,u32 val)60959f85f8SPaul Mundt static int sh4_pci_write(struct pci_bus *bus, unsigned int devfn,
61959f85f8SPaul Mundt int where, int size, u32 val)
62959f85f8SPaul Mundt {
63b6706ef1SMagnus Damm struct pci_channel *chan = bus->sysdata;
64959f85f8SPaul Mundt unsigned long flags;
65959f85f8SPaul Mundt int shift;
66959f85f8SPaul Mundt u32 data;
67959f85f8SPaul Mundt
6839a90865SPaul Mundt raw_spin_lock_irqsave(&pci_config_lock, flags);
69b6706ef1SMagnus Damm pci_write_reg(chan, CONFIG_CMD(bus, devfn, where), SH4_PCIPAR);
70b6706ef1SMagnus Damm data = pci_read_reg(chan, SH4_PCIPDR);
7139a90865SPaul Mundt raw_spin_unlock_irqrestore(&pci_config_lock, flags);
72959f85f8SPaul Mundt
73959f85f8SPaul Mundt switch (size) {
74959f85f8SPaul Mundt case 1:
75959f85f8SPaul Mundt shift = (where & 3) << 3;
76959f85f8SPaul Mundt data &= ~(0xff << shift);
77959f85f8SPaul Mundt data |= ((val & 0xff) << shift);
78959f85f8SPaul Mundt break;
79959f85f8SPaul Mundt case 2:
80959f85f8SPaul Mundt shift = (where & 2) << 3;
81959f85f8SPaul Mundt data &= ~(0xffff << shift);
82959f85f8SPaul Mundt data |= ((val & 0xffff) << shift);
83959f85f8SPaul Mundt break;
84959f85f8SPaul Mundt case 4:
85959f85f8SPaul Mundt data = val;
86959f85f8SPaul Mundt break;
87959f85f8SPaul Mundt default:
88959f85f8SPaul Mundt return PCIBIOS_FUNC_NOT_SUPPORTED;
89959f85f8SPaul Mundt }
90959f85f8SPaul Mundt
91b6706ef1SMagnus Damm pci_write_reg(chan, data, SH4_PCIPDR);
92959f85f8SPaul Mundt
93959f85f8SPaul Mundt return PCIBIOS_SUCCESSFUL;
94959f85f8SPaul Mundt }
95959f85f8SPaul Mundt
96959f85f8SPaul Mundt struct pci_ops sh4_pci_ops = {
97959f85f8SPaul Mundt .read = sh4_pci_read,
98959f85f8SPaul Mundt .write = sh4_pci_write,
99959f85f8SPaul Mundt };
100959f85f8SPaul Mundt
pci_fixup_pcic(struct pci_channel * chan)101b8b47bfbSMagnus Damm int __attribute__((weak)) pci_fixup_pcic(struct pci_channel *chan)
102cd6c7ea2SPaul Mundt {
103cd6c7ea2SPaul Mundt /* Nothing to do. */
104cd6c7ea2SPaul Mundt return 0;
105cd6c7ea2SPaul Mundt }
106