blob: 12cea5b5209c955eb89f5c1d8238e8a1f8ae02ec [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.
*/
#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;
}