diff options
Diffstat (limited to 'hw/gx.c')
-rw-r--r-- | hw/gx.c | 158 |
1 files changed, 158 insertions, 0 deletions
@@ -0,0 +1,158 @@ +/* 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. + */ + +#include <skiboot.h> +#include <gx.h> +#include <xscom.h> + +/* + * Note: This file os only used on P7/P7+ + */ + +/* Configuration of the PSI BUID, see the explanation in + * interrupts.h + */ +static int gx_p7_configure_psi_buid(uint32_t chip, uint32_t buid) +{ + uint64_t mode1; + int rc; + + rc = xscom_read(chip, GX_P7_MODE1_REG, &mode1); + if (rc) { + prerror("GX: XSCOM error %d reading GX MODE1 REG\n", rc); + return rc; + } + + mode1 = SETFIELD(GX_P7_MODE1_PSI_BUID, mode1, buid); + mode1 &= ~GX_P7_MODE1_PSI_BUID_DISABLE; + + printf("GX: MODE1_REG set to 0x%llx\n", mode1); + rc = xscom_write(chip, GX_P7_MODE1_REG, mode1); + if (rc) { + prerror("GX: XSCOM error %d writing GX MODE1 REG\n", rc); + return rc; + } + + return 0; +} + +static int gx_p7p_configure_psi_buid(uint32_t chip, uint32_t buid) +{ + uint64_t mode4; + int rc; + + rc = xscom_read(chip, GX_P7P_MODE4_REG, &mode4); + if (rc) { + prerror("GX: XSCOM error %d reading GX MODE1 REG\n", rc); + return rc; + } + + mode4 = SETFIELD(GX_P7P_MODE4_PSI_BUID, mode4, buid); + mode4 &= ~GX_P7P_MODE4_PSI_BUID_DISABLE; + + rc = xscom_write(chip, GX_P7P_MODE4_REG, mode4); + if (rc) { + prerror("GX: XSCOM error %d writing GX MODE1 REG\n", rc); + return rc; + } + + return 0; +} + +/* Configure the BUID of the PSI interrupt in the GX + * controller. + * + * @chip: Chip number (0..31) + * @buid: 9-bit BUID value + */ +int gx_configure_psi_buid(uint32_t chip, uint32_t buid) +{ + uint32_t pvr = mfspr(SPR_PVR); + + printf("GX: PSI BUID for PVR %x (type %x) chip %d BUID 0x%x\n", + pvr, PVR_TYPE(pvr), chip, buid); + + switch(PVR_TYPE(pvr)) { + case PVR_TYPE_P7: + return gx_p7_configure_psi_buid(chip, buid); + case PVR_TYPE_P7P: + return gx_p7p_configure_psi_buid(chip, buid); + } + return -1; +} + + +static int gx_p7_configure_tce_bar(uint32_t chip, uint32_t gx, uint64_t addr, + uint64_t size) +{ + uint32_t areg, mreg; + int rc; + + switch (gx) { + case 0: + areg = GX_P7_GX0_TCE_BAR; + mreg = GX_P7_GX0_TCE_MASK; + break; + case 1: + areg = GX_P7_GX1_TCE_BAR; + mreg = GX_P7_GX1_TCE_MASK; + break; + default: + return -EINVAL; + } + + if (addr) { + uint64_t taddr, tmask; + + /* The address field contains bits 18 to 43 of the address */ + taddr = SETFIELD(GX_P7_TCE_BAR_ADDR, 0ul, + (addr >> GX_P7_TCE_BAR_ADDR_SHIFT)); + taddr |= GX_P7_TCE_BAR_ENABLE; + tmask = SETFIELD(GX_P7_TCE_MASK, 0ul, + ~((size - 1) >> GX_P7_TCE_BAR_ADDR_SHIFT)); + rc = xscom_write(chip, areg, 0); + rc |= xscom_write(chip, mreg, tmask); + rc |= xscom_write(chip, areg, taddr); + } else { + rc = xscom_write(chip, areg, 0); + } + return rc ? -EIO : 0; +} + +/* Configure the TCE BAR of a given GX bus + * + * @chip: Chip number (0..31) + * @gx : GX bus index + * @addr: base address of TCE table + * @size: size of TCE table + */ +int gx_configure_tce_bar(uint32_t chip, uint32_t gx, uint64_t addr, + uint64_t size) +{ + uint32_t pvr = mfspr(SPR_PVR); + + printf("GX: TCE BAR for PVR %x (type %x) chip %d gx %d\n", + pvr, PVR_TYPE(pvr), chip, gx); + + /* We only support P7... is there a P7+ with P5IOC2 ? */ + switch(PVR_TYPE(pvr)) { + case PVR_TYPE_P7: + return gx_p7_configure_tce_bar(chip, gx, addr, size); + } + return -EINVAL; +} + + |