1/*
2 * Copyright 2007, François Revol <revol@free.fr>.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5
6#include "pci_atari.h"
7
8#include <stdlib.h>
9#include <string.h>
10
11#include <KernelExport.h>
12#include <PCI.h>
13
14#include "pci_controller.h"
15
16/*
17 * Here we fake a PCI bus that maps the physical memory
18 * (which is also I/O on 68k), and fake some system devices.
19 * Some other devices are faked as ISA because they need DMA
20 * notification.
21 *
22 * TODO: anything to be done to support VME cards ?
23 * I don't think they are PnP at all anyway.
24 *
25 * TODO: On Hades/Milan clones a real PCI bus is accessible
26 * through PAE-like extra bits in page descriptors. This one
27 * should be handled in a separate file.
28 */
29
30//XXX:find one and put in shared priv header!
31// 0x68xx is free according to pci.ids
32// 68fx (f=fake) x = 0:amiga, 1:apple, 2:atari
33#define FAKEV 0x68f2
34
35// bus number
36#define BN 0
37
38// default line size
39#define DLL 1
40// default latency
41#define DL 0
42// default bist
43#define DB 0
44
45#define PEI 0
46
47#define INVV 0xffff //0x0000 ??
48#define INVD 0xffff
49
50struct fake_pci_device {
51	pci_info info;
52
53};
54
55static struct fake_pci_device gFakePCIDevices[] = {
56{ {FAKEV, 0x0000, BN, 0, 0, 0, 0xff, PCI_host, PCI_bridge, DLL, DL, DB, 0, PEI }}, /* cpu */
57{ {FAKEV, 0x0001, BN, 1, 0, 0, 0xff, 0x68/*fake*/, PCI_processor, DLL, DL, DB, 0, PEI }}, /* cpu */
58{ {FAKEV, 0x0002, BN, 2, 0, 0, 0xff, PCI_display_other, PCI_display, DLL, DL, DB, 0, 0xFFFF8200, PEI }}, /* gfx */
59{ {FAKEV, 0x0003, BN, 3, 0, 0, 0xff, PCI_ide, PCI_mass_storage, DLL, DL, DB, 0, 0xFFF00000, PEI }}, /* ide */
60{ {FAKEV, 0x0004, BN, 4, 0, 0, 0xff, PCI_scsi, PCI_mass_storage, DLL, DL, DB, 0, PEI }}, /* scsi */
61{ {FAKEV, 0x0005, BN, 5, 0, 0, 0xff, 0x0/*CHANGEME*/, PCI_multimedia, DLL, DL, DB, 0x00, 0, 0xFFFF8900, PEI }}, /* snd */
62//UART ?
63//centronics?
64{ {INVV, INVD} }
65};
66#define FAKE_DEVICES_COUNT (sizeof(gFakePCIDevices)/sizeof(struct fake_pci_device)-1)
67
68struct m68k_atari_fake_host_bridge {
69	uint32					bus;
70};
71
72
73#define out8rb(address, value)	m68k_out8((vuint8*)(address), value)
74#define out16rb(address, value)	m68k_out16_reverse((vuint16*)(address), value)
75#define out32rb(address, value)	m68k_out32_reverse((vuint32*)(address), value)
76#define in8rb(address)			m68k_in8((const vuint8*)(address))
77#define in16rb(address)			m68k_in16_reverse((const vuint16*)(address))
78#define in32rb(address)			m68k_in32_reverse((const vuint32*)(address))
79
80
81static int		m68k_atari_enable_config(struct m68k_atari_fake_host_bridge *bridge,
82					uint8 bus, uint8 slot, uint8 function, uint8 offset);
83
84static status_t	m68k_atari_read_pci_config(void *cookie, uint8 bus, uint8 device,
85					uint8 function, uint8 offset, uint8 size, uint32 *value);
86static status_t	m68k_atari_write_pci_config(void *cookie, uint8 bus,
87					uint8 device, uint8 function, uint8 offset, uint8 size,
88					uint32 value);
89static status_t	m68k_atari_get_max_bus_devices(void *cookie, int32 *count);
90static status_t	m68k_atari_read_pci_irq(void *cookie, uint8 bus, uint8 device,
91					uint8 function, uint8 pin, uint8 *irq);
92static status_t	m68k_atari_write_pci_irq(void *cookie, uint8 bus, uint8 device,
93					uint8 function, uint8 pin, uint8 irq);
94
95static pci_controller sM68kAtariPCIController = {
96	m68k_atari_read_pci_config,
97	m68k_atari_write_pci_config,
98	m68k_atari_get_max_bus_devices,
99	m68k_atari_read_pci_irq,
100	m68k_atari_write_pci_irq,
101};
102
103
104static status_t
105m68k_atari_read_pci_config(void *cookie, uint8 bus, uint8 device, uint8 function,
106	uint8 offset, uint8 size, uint32 *value)
107{
108	struct fake_pci_device *devices = (struct fake_pci_device *)cookie;
109	struct fake_pci_device *dev;
110
111	if (bus != 0)
112		return EINVAL;
113	if (device >= FAKE_DEVICES_COUNT)
114		return EINVAL;
115	if (function != 0)
116		return EINVAL;
117	dev = &devices[device];
118
119#define O(pn,n,s)			\
120	case pn:				\
121		if (size != s) {	\
122			panic("invalid pci config size %d for offset %d", size, offset); \
123			return EINVAL;	\
124		}			\
125		*value = dev->info.n;	\
126		return B_OK
127
128	if (1) {
129		switch (offset) {
130		O(PCI_vendor_id, vendor_id, 2);
131		O(PCI_device_id, device_id, 2);
132		O(PCI_revision, revision, 1);
133		O(PCI_class_api, class_api, 1);
134		O(PCI_class_sub, class_sub, 1);
135		O(PCI_class_base, class_base, 1);
136		O(PCI_line_size, line_size, 1);
137		O(PCI_latency, latency, 1);
138		O(PCI_header_type, header_type, 1);
139		O(PCI_bist, bist, 1);
140		}
141	}
142//#undef O
143#if 0
144#define PCI_command                             0x04            /* (2 byte) command */
145#define PCI_status                              0x06            /* (2 byte) status */
146#endif
147
148	if (dev->info.header_type == 0x00 || dev->info.header_type == 0x01) {
149		switch (offset) {
150		case PCI_base_registers:
151			return EINVAL;
152		O(PCI_interrupt_line, u.h0.interrupt_line, 1);
153		O(PCI_interrupt_pin, u.h0.interrupt_pin, 1);
154			default:
155				break;
156		}
157	}
158
159	if (dev->info.header_type == 0x00) {
160		switch (offset) {
161			default:
162				break;
163		}
164	}
165
166	if (dev->info.header_type == 0x01) {
167		switch (offset) {
168		O(PCI_primary_bus, u.h1.primary_bus, 1);
169		O(PCI_secondary_bus, u.h1.secondary_bus, 1);
170		O(PCI_subordinate_bus, u.h1.subordinate_bus, 1);
171		O(PCI_secondary_latency, u.h1.secondary_latency, 1);
172			default:
173				break;
174		}
175	}
176
177	*value = 0xffffffff;
178	panic("invalid pci config offset %d", offset);
179	return EINVAL;
180	//return B_OK;
181}
182
183
184static status_t
185m68k_atari_write_pci_config(void *cookie, uint8 bus, uint8 device,
186	uint8 function, uint8 offset, uint8 size, uint32 value)
187{
188#if 0
189	if (m68k_atari_enable_config(bridge, bus, device, function, offset)) {
190		switch (size) {
191			case 1:
192				out8rb(caoff, (uint8)value);
193				(void)in8rb(caoff);
194				break;
195			case 2:
196				out16rb(caoff, (uint16)value);
197				(void)in16rb(caoff);
198				break;
199			case 4:
200				out32rb(caoff, value);
201				(void)in32rb(caoff);
202				break;
203		}
204	}
205
206#endif
207	panic("write pci config dev %d offset %d", device, offset);
208	return B_ERROR;
209	return B_OK;
210}
211
212
213static status_t
214m68k_atari_get_max_bus_devices(void *cookie, int32 *count)
215{
216	*count = 32;
217	return B_OK;
218}
219
220
221static status_t
222m68k_atari_read_pci_irq(void *cookie, uint8 bus, uint8 device,
223	uint8 function, uint8 pin, uint8 *irq)
224{
225#warning M68K: WRITEME
226	return B_ERROR;
227}
228
229
230static status_t
231m68k_atari_write_pci_irq(void *cookie, uint8 bus, uint8 device,
232	uint8 function, uint8 pin, uint8 irq)
233{
234#warning M68K: WRITEME
235	return B_ERROR;
236}
237
238
239// #pragma mark -
240
241
242static int
243m68k_atari_enable_config(struct m68k_atari_fake_host_bridge *bridge, uint8 bus,
244	uint8 slot, uint8 function, uint8 offset)
245{
246#warning M68K: WRITEME
247	return 0;
248}
249
250
251// #pragma mark -
252
253
254
255
256status_t
257m68k_atari_pci_controller_init(void)
258{
259	struct m68k_atari_fake_host_bridge *bridge;
260	bridge = (struct m68k_atari_fake_host_bridge *)
261		malloc(sizeof(struct m68k_atari_fake_host_bridge));
262	if (!bridge)
263		return B_NO_MEMORY;
264
265	bridge->bus = 0;
266
267	status_t error = pci_controller_add(&sM68kAtariPCIController, bridge);
268
269	if (error != B_OK)
270		free(bridge);
271
272	// TODO: probe Hades & Milan bridges
273	return error;
274}
275
276
277// #pragma mark - support functions
278
279
280