blob: fb9ed1bb483fa5e6214abf5db37362e55322574f [file] [log] [blame]
/* Copyright 2013-2014 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __P5IOC2_H
#define __P5IOC2_H
#include <stdint.h>
#include <cec.h>
#include <io.h>
#include <cec.h>
#include <pci.h>
#include <lock.h>
#include <device.h>
#include <ccan/container_of/container_of.h>
/*
* Various definitions which are the result of various
* things we have hard wired (routing etc...)
*/
/* It looks like our registers are at an offset from GX BAR 0 ... */
#define P5IOC2_REGS_OFFSET 0x01F00000
#define P5IOC2_CA0_REG_OFFSET 0 /* From BAR6, R0 */
#define P5IOC2_CA1_REG_OFFSET 0x01000000 /* From BAR6, R1 */
#define P5IOC2_CA0_MM_OFFSET 0 /* From BAR0, R0 and 1 */
#define P5IOC2_CA1_MM_OFFSET 0x400000000ul /* From BAR0, R1 and 2 */
#define P5IOC2_CA_PHB_COUNT 4
#define P5IOC2_CA0_RIO_ID 2
#define P5IOC2_CA1_RIO_ID 3
#define P5IOC2_CA0_BUID 0x10
#define P5IOC2_CA1_BUID 0x20
/*
* Our memory space is slightly different than pHyp
* (or even BML). We do as follow:
*
* - IO space is in the Calgary MMIO, at (phb_index +1) * 1M
* (pHyp seems to mangle the IO space location) and is always
* 1M in size mapping to PCI 0
*
* - Memory space is in the BAR0 mapped region. Each PHB gets
* allocated a 4G window at base + (phb_index * 4G). It uses
* a portion of that space based on the chosen size of the
* MMIO space, typically 2G.
*/
#define MM_WINDOW_SIZE 0x100000000ul
#define MM_PCI_START 0x80000000
#define MM_PCI_SIZE 0x80000000
#define IO_PCI_START 0x00000000
#define IO_PCI_SIZE 0x00100000
/*
* CAn interrupts
*
* Within Calgary BUID space
*/
#define P5IOC2_CA_HOST_IRQ 0
#define P5IOC2_CA_SPCN_IRQ 1
#define P5IOC2_CA_PERF_IRQ 2
/*
* The PHB states are similar to P7IOC, see the explanation
* in p7ioc.h
*/
enum p5ioc2_phb_state {
/* First init state */
P5IOC2_PHB_STATE_UNINITIALIZED,
/* During PHB HW inits */
P5IOC2_PHB_STATE_INITIALIZING,
/* Set if the PHB is for some reason unusable */
P5IOC2_PHB_STATE_BROKEN,
/* Normal PHB functional state */
P5IOC2_PHB_STATE_FUNCTIONAL,
};
/*
* Structure for a PHB
*/
struct p5ioc2;
struct p5ioc2_phb {
bool active; /* Is this PHB functional ? */
bool is_pcie;
uint8_t ca; /* CA0 or CA1 */
uint8_t index; /* 0..3 index inside CA */
void *ca_regs; /* Calgary regs */
void *regs; /* PHB regs */
struct lock lock;
uint32_t buid;
uint64_t mm_base;
uint64_t io_base;
int64_t ecap; /* cached PCI-E cap offset */
int64_t aercap; /* cached AER ecap offset */
enum p5ioc2_phb_state state;
uint64_t delay_tgt_tb;
uint64_t retries;
uint64_t xive_cache[16];
struct p5ioc2 *ioc;
struct phb phb;
};
static inline struct p5ioc2_phb *phb_to_p5ioc2_phb(struct phb *phb)
{
return container_of(phb, struct p5ioc2_phb, phb);
}
extern void p5ioc2_phb_setup(struct p5ioc2 *ioc, struct p5ioc2_phb *p,
uint8_t ca, uint8_t index, bool active,
uint32_t buid);
/*
* State structure for P5IOC2 IO HUB
*/
struct p5ioc2 {
/* Device node */
struct dt_node *dt_node;
/* MMIO regs for the chip */
void *regs;
/* BAR6 (matches GX BAR 1) is used for internal Calgary MMIO and
* for PCI IO space.
*/
uint64_t bar6;
/* BAR0 (matches GX BAR 2) is used for PCI memory space */
uint64_t bar0;
/* Calgary 0 and 1 registers. We assume their BBAR values as such
* that CA0 is at bar6 and CA1 at bar6 + 16M
*/
void* ca0_regs;
void* ca1_regs;
/* The large MM regions assigned off bar0 to CA0 and CA1 for use
* by their PHBs (16G each)
*/
uint64_t ca0_mm_region;
uint64_t ca1_mm_region;
/* BUID base for the PHB. This does include the top bits
* (chip, GX bus ID, etc...). This is initialized from the
* SPIRA.
*/
uint32_t buid_base;
/* TCE region set by the user */
uint64_t tce_base;
uint64_t tce_size;
/* Calgary 0 and 1 PHBs */
struct p5ioc2_phb ca0_phbs[P5IOC2_CA_PHB_COUNT];
struct p5ioc2_phb ca1_phbs[P5IOC2_CA_PHB_COUNT];
uint32_t host_chip;
uint32_t gx_bus;
struct io_hub hub;
};
static inline struct p5ioc2 *iohub_to_p5ioc2(struct io_hub *hub)
{
return container_of(hub, struct p5ioc2, hub);
}
#endif /* __P5IOC2_H */