Deleted Added
sdiff udiff text old ( 239277 ) new ( 240489 )
full compact
1/*-
2 * Copyright (c) 2008 MARVELL INTERNATIONAL LTD.
3 * Copyright (c) 2010 The FreeBSD Foundation
4 * All rights reserved.
5 *
6 * Developed by Semihalf.
7 *
8 * Portions of this software were developed by Semihalf
9 * under sponsorship from the FreeBSD Foundation.
10 *
11 * Redistribution and use in source and binary forms, with or without

--- 21 unchanged lines hidden (view full) ---

33 * SUCH DAMAGE.
34 */
35
36/*
37 * Marvell integrated PCI/PCI-Express controller driver.
38 */
39
40#include <sys/cdefs.h>
41__FBSDID("$FreeBSD: head/sys/arm/mv/mv_pci.c 239277 2012-08-15 05:15:49Z gonzo $");
42
43#include <sys/param.h>
44#include <sys/systm.h>
45#include <sys/kernel.h>
46#include <sys/lock.h>
47#include <sys/malloc.h>
48#include <sys/module.h>
49#include <sys/mutex.h>

--- 34 unchanged lines hidden (view full) ---

84
85#define PCIE_REG_CFG_ADDR 0x18F8
86#define PCIE_REG_CFG_DATA 0x18FC
87#define PCIE_REG_CONTROL 0x1A00
88#define PCIE_CTRL_LINK1X 0x00000001
89#define PCIE_REG_STATUS 0x1A04
90#define PCIE_REG_IRQ_MASK 0x1910
91
92#define STATUS_LINK_DOWN 1
93#define STATUS_BUS_OFFS 8
94#define STATUS_BUS_MASK (0xFF << STATUS_BUS_OFFS)
95#define STATUS_DEV_OFFS 16
96#define STATUS_DEV_MASK (0x1F << STATUS_DEV_OFFS)
97
98#define P2P_CONF_BUS_OFFS 16
99#define P2P_CONF_BUS_MASK (0xFF << P2P_CONF_BUS_OFFS)
100#define P2P_CONF_DEV_OFFS 24
101#define P2P_CONF_DEV_MASK (0x1F << P2P_CONF_DEV_OFFS)
102
103#define PCI_VENDORID_MRVL 0x11AB
104
105struct mv_pcib_softc {
106 device_t sc_dev;
107
108 struct rman sc_mem_rman;
109 bus_addr_t sc_mem_base;
110 bus_addr_t sc_mem_size;
111 bus_addr_t sc_mem_alloc; /* Next allocation. */
112 int sc_mem_win_target;
113 int sc_mem_win_attr;
114
115 struct rman sc_io_rman;
116 bus_addr_t sc_io_base;
117 bus_addr_t sc_io_size;
118 bus_addr_t sc_io_alloc; /* Next allocation. */
119 int sc_io_win_target;
120 int sc_io_win_attr;
121
122 struct resource *sc_res;
123 bus_space_handle_t sc_bsh;
124 bus_space_tag_t sc_bst;
125 int sc_rid;
126
127 int sc_busnr; /* Host bridge bus number */
128 int sc_devnr; /* Host bridge device number */
129 int sc_type;
130
131 struct fdt_pci_intr sc_intr_info;
132};
133
134/* Local forward prototypes */
135static int mv_pcib_decode_win(phandle_t, struct mv_pcib_softc *);
136static void mv_pcib_hw_cfginit(void);
137static uint32_t mv_pcib_hw_cfgread(struct mv_pcib_softc *, u_int, u_int,
138 u_int, u_int, int);
139static void mv_pcib_hw_cfgwrite(struct mv_pcib_softc *, u_int, u_int,
140 u_int, u_int, uint32_t, int);
141static int mv_pcib_init(struct mv_pcib_softc *, int, int);
142static int mv_pcib_init_all_bars(struct mv_pcib_softc *, int, int, int, int);
143static void mv_pcib_init_bridge(struct mv_pcib_softc *, int, int, int);
144static int mv_pcib_intr_info(phandle_t, struct mv_pcib_softc *);
145static inline void pcib_write_irq_mask(struct mv_pcib_softc *, uint32_t);
146
147
148/* Forward prototypes */
149static int mv_pcib_probe(device_t);
150static int mv_pcib_attach(device_t);
151
152static struct resource *mv_pcib_alloc_resource(device_t, device_t, int, int *,
153 u_long, u_long, u_long, u_int);
154static int mv_pcib_release_resource(device_t, device_t, int, int,
155 struct resource *);

--- 24 unchanged lines hidden (view full) ---

180 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
181 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
182
183 /* pcib interface */
184 DEVMETHOD(pcib_maxslots, mv_pcib_maxslots),
185 DEVMETHOD(pcib_read_config, mv_pcib_read_config),
186 DEVMETHOD(pcib_write_config, mv_pcib_write_config),
187 DEVMETHOD(pcib_route_interrupt, mv_pcib_route_interrupt),
188
189 /* OFW bus interface */
190 DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat),
191 DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model),
192 DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name),
193 DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node),
194 DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type),
195
196 DEVMETHOD_END

--- 28 unchanged lines hidden (view full) ---

225 return (BUS_PROBE_DEFAULT);
226}
227
228static int
229mv_pcib_attach(device_t self)
230{
231 struct mv_pcib_softc *sc;
232 phandle_t node, parnode;
233 uint32_t val;
234 int err;
235
236 sc = device_get_softc(self);
237 sc->sc_dev = self;
238
239 node = ofw_bus_get_node(self);
240 parnode = OF_parent(node);
241 if (fdt_is_compatible(node, "mrvl,pcie")) {
242 sc->sc_type = MV_TYPE_PCIE;
243 sc->sc_mem_win_target = MV_WIN_PCIE_TARGET(0);
244 sc->sc_mem_win_attr = MV_WIN_PCIE_MEM_ATTR(0);
245 sc->sc_io_win_target = MV_WIN_PCIE_TARGET(0);
246 sc->sc_io_win_attr = MV_WIN_PCIE_IO_ATTR(0);
247#ifdef SOC_MV_ORION
248 } else if (fdt_is_compatible(node, "mrvl,pci")) {
249 sc->sc_type = MV_TYPE_PCI;
250 sc->sc_mem_win_target = MV_WIN_PCI_TARGET;
251 sc->sc_mem_win_attr = MV_WIN_PCI_MEM_ATTR;
252 sc->sc_io_win_target = MV_WIN_PCI_TARGET;
253 sc->sc_io_win_attr = MV_WIN_PCI_IO_ATTR;
254#endif
255 } else
256 return (ENXIO);
257
258 /*
259 * Get PCI interrupt info.
260 */
261 if (mv_pcib_intr_info(node, sc) != 0) {
262 device_printf(self, "could not retrieve interrupt info\n");
263 return (ENXIO);
264 }
265
266 /*
267 * Retrieve our mem-mapped registers range.
268 */
269 sc->sc_rid = 0;
270 sc->sc_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &sc->sc_rid,
271 RF_ACTIVE);
272 if (sc->sc_res == NULL) {
273 device_printf(self, "could not map memory\n");
274 return (ENXIO);
275 }
276 sc->sc_bst = rman_get_bustag(sc->sc_res);
277 sc->sc_bsh = rman_get_bushandle(sc->sc_res);
278
279 /*
280 * Configure decode windows for PCI(E) access.
281 */
282 if (mv_pcib_decode_win(node, sc) != 0)
283 return (ENXIO);
284
285 mv_pcib_hw_cfginit();
286
287 /*
288 * Enable PCI bridge.
289 */
290 val = mv_pcib_hw_cfgread(sc, sc->sc_busnr, sc->sc_devnr, 0,
291 PCIR_COMMAND, 2);
292 val |= PCIM_CMD_SERRESPEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN |
293 PCIM_CMD_PORTEN;
294 mv_pcib_hw_cfgwrite(sc, sc->sc_busnr, sc->sc_devnr, 0,
295 PCIR_COMMAND, val, 2);
296
297 sc->sc_mem_alloc = sc->sc_mem_base;
298 sc->sc_io_alloc = sc->sc_io_base;
299
300 sc->sc_mem_rman.rm_type = RMAN_ARRAY;
301 err = rman_init(&sc->sc_mem_rman);
302 if (err)
303 return (err);
304
305 sc->sc_io_rman.rm_type = RMAN_ARRAY;
306 err = rman_init(&sc->sc_io_rman);
307 if (err) {

--- 6 unchanged lines hidden (view full) ---

314 if (err)
315 goto error;
316
317 err = rman_manage_region(&sc->sc_io_rman, sc->sc_io_base,
318 sc->sc_io_base + sc->sc_io_size - 1);
319 if (err)
320 goto error;
321
322 err = mv_pcib_init(sc, sc->sc_busnr, mv_pcib_maxslots(sc->sc_dev));
323 if (err)
324 goto error;
325
326 device_add_child(self, "pci", -1);
327 return (bus_generic_attach(self));
328
329error:
330 /* XXX SYS_RES_ should be released here */
331 rman_fini(&sc->sc_mem_rman);
332 rman_fini(&sc->sc_io_rman);
333 return (err);
334}
335
336static int
337mv_pcib_init_bar(struct mv_pcib_softc *sc, int bus, int slot, int func,
338 int barno)
339{
340 bus_addr_t *allocp, limit;
341 uint32_t addr, bar, mask, size;
342 int reg, width;
343
344 reg = PCIR_BAR(barno);
345 bar = mv_pcib_read_config(sc->sc_dev, bus, slot, func, reg, 4);
346 if (bar == 0)
347 return (1);
348
349 /* Calculate BAR size: 64 or 32 bit (in 32-bit units) */
350 width = ((bar & 7) == 4) ? 2 : 1;
351
352 mv_pcib_write_config(sc->sc_dev, bus, slot, func, reg, ~0, 4);
353 size = mv_pcib_read_config(sc->sc_dev, bus, slot, func, reg, 4);
354
355 /* Get BAR type and size */
356 if (bar & 1) {
357 /* I/O port */
358 allocp = &sc->sc_io_alloc;
359 limit = sc->sc_io_base + sc->sc_io_size;
360 size &= ~0x3;
361 if ((size & 0xffff0000) == 0)
362 size |= 0xffff0000;
363 } else {
364 /* Memory */
365 allocp = &sc->sc_mem_alloc;
366 limit = sc->sc_mem_base + sc->sc_mem_size;
367 size &= ~0xF;
368 }
369 mask = ~size;
370 size = mask + 1;
371
372 /* Sanity check (must be a power of 2) */
373 if (size & mask)
374 return (width);
375
376 addr = (*allocp + mask) & ~mask;
377 if ((*allocp = addr + size) > limit)
378 return (-1);
379
380 if (bootverbose)
381 printf("PCI %u:%u:%u: reg %x: size=%08x: addr=%08x\n",
382 bus, slot, func, reg, size, addr);
383
384 mv_pcib_write_config(sc->sc_dev, bus, slot, func, reg, addr, 4);
385 if (width == 2)
386 mv_pcib_write_config(sc->sc_dev, bus, slot, func, reg + 4,
387 0, 4);
388
389 return (width);
390}

--- 132 unchanged lines hidden (view full) ---

523 switch (type) {
524 case SYS_RES_IOPORT:
525 rm = &sc->sc_io_rman;
526 break;
527 case SYS_RES_MEMORY:
528 rm = &sc->sc_mem_rman;
529 break;
530 default:
531 return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
532 type, rid, start, end, count, flags));
533 };
534
535 res = rman_reserve_resource(rm, start, end, count, flags, child);
536 if (res == NULL)
537 return (NULL);
538
539 rman_set_rid(res, *rid);
540 rman_set_bustag(res, fdtbus_bs_tag);
541 rman_set_bushandle(res, start);
542

--- 148 unchanged lines hidden (view full) ---

691}
692
693static uint32_t
694mv_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func,
695 u_int reg, int bytes)
696{
697 struct mv_pcib_softc *sc = device_get_softc(dev);
698
699 /* Skip self */
700 if (bus == sc->sc_busnr && slot == sc->sc_devnr)
701 return (~0U);
702
703 return (mv_pcib_hw_cfgread(sc, bus, slot, func, reg, bytes));
704}
705
706static void
707mv_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func,
708 u_int reg, uint32_t val, int bytes)
709{
710 struct mv_pcib_softc *sc = device_get_softc(dev);
711
712 /* Skip self */
713 if (bus == sc->sc_busnr && slot == sc->sc_devnr)
714 return;
715
716 mv_pcib_hw_cfgwrite(sc, bus, slot, func, reg, val, bytes);
717}
718
719static int
720mv_pcib_route_interrupt(device_t pcib, device_t dev, int pin)
721{

--- 22 unchanged lines hidden (view full) ---

744 dev = sc->sc_dev;
745
746 if ((error = fdt_pci_ranges(node, &io_space, &mem_space)) != 0) {
747 device_printf(dev, "could not retrieve 'ranges' data\n");
748 return (error);
749 }
750
751 /* Configure CPU decoding windows */
752 error = decode_win_cpu_set(sc->sc_io_win_target,
753 sc->sc_io_win_attr, io_space.base_parent, io_space.len, -1);
754 if (error < 0) {
755 device_printf(dev, "could not set up CPU decode "
756 "window for PCI IO\n");
757 return (ENXIO);
758 }
759 error = decode_win_cpu_set(sc->sc_mem_win_target,
760 sc->sc_mem_win_attr, mem_space.base_parent, mem_space.len, -1);
761 if (error < 0) {
762 device_printf(dev, "could not set up CPU decode "
763 "windows for PCI MEM\n");
764 return (ENXIO);
765 }
766
767 sc->sc_io_base = io_space.base_parent;
768 sc->sc_io_size = io_space.len;

--- 10 unchanged lines hidden (view full) ---

779 int error;
780
781 if ((error = fdt_pci_intr_info(node, &sc->sc_intr_info)) != 0)
782 return (error);
783
784 return (0);
785}
786
787#if 0
788 control = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
789 PCIE_REG_CONTROL);
790
791 /*
792 * If this PCI-E port (controller) is configured (by the
793 * underlying firmware) with lane width other than 1x, there
794 * are auxiliary resources defined for aggregating more width
795 * on our lane. Skip all such entries as they are not
796 * standalone ports and must not have a device object
797 * instantiated.
798 */
799 if ((control & PCIE_CTRL_LINK1X) == 0)
800 while (info->op_base &&
801 info->op_type == MV_TYPE_PCIE_AGGR_LANE)
802 info++;
803
804 mv_pcib_add_child(driver, parent, sc);
805#endif