Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a driver for the SCOM ranges of the OCMB. Unlike most chips the OCMB has two different (three if you count OpenCAPI config space) register spaces and we need to ensure that the right access size is used on each. Additionally the SCOM interface is a bit non-standard in that a full physical address is passed as the SCOM address rather than a register number so we don't need to perform any address transformations, we just need to verify that the address falls into one of the nominated address ranges. Cc: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com> Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
- Loading branch information
Showing
4 changed files
with
185 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later | ||
/* | ||
* Open Capi Memory Buffer chip | ||
* | ||
* Copyright 2020 IBM Corp. | ||
*/ | ||
|
||
|
||
#define pr_fmt(fmt) "OCMB: " fmt | ||
|
||
#include <skiboot.h> | ||
#include <xscom.h> | ||
#include <device.h> | ||
#include <ocmb.h> | ||
#include <io.h> | ||
#include <inttypes.h> | ||
|
||
struct ocmb_range { | ||
uint64_t start; | ||
uint64_t end; | ||
uint64_t flags; | ||
|
||
/* flags come from hdat */ | ||
#define ACCESS_8B PPC_BIT(0) | ||
#define ACCESS_4B PPC_BIT(1) | ||
#define ACCESS_SIZE_MASK (ACCESS_8B | ACCESS_4B) | ||
}; | ||
|
||
struct ocmb { | ||
struct scom_controller scom; | ||
int range_count; | ||
struct ocmb_range ranges[]; | ||
}; | ||
|
||
static const struct ocmb_range *find_range(const struct ocmb *o, uint64_t offset) | ||
{ | ||
int i; | ||
|
||
for (i = 0; i < o->range_count; i++) { | ||
uint64_t start = o->ranges[i].start; | ||
uint64_t end = o->ranges[i].end; | ||
|
||
if (offset >= start && offset <= end) | ||
return &o->ranges[i]; | ||
} | ||
|
||
return NULL; | ||
} | ||
|
||
static int64_t ocmb_fake_scom_write(struct scom_controller *f, | ||
uint32_t __unused chip_id, | ||
uint64_t offset, uint64_t val) | ||
{ | ||
const struct ocmb *o = f->private; | ||
const struct ocmb_range *r; | ||
|
||
r = find_range(o, offset); | ||
if (!r) { | ||
prerror("no matching address range!\n"); | ||
return OPAL_XSCOM_ADDR_ERROR; | ||
} | ||
|
||
switch (r->flags & ACCESS_SIZE_MASK) { | ||
case ACCESS_8B: | ||
if (offset & 0x7) | ||
return OPAL_XSCOM_ADDR_ERROR; | ||
out_be64((void *) offset, val); | ||
break; | ||
|
||
case ACCESS_4B: | ||
if (offset & 0x3) | ||
return OPAL_XSCOM_ADDR_ERROR; | ||
out_be32((void *) offset, val); | ||
break; | ||
default: | ||
prerror("bad flags? %llx\n", r->flags); | ||
return OPAL_XSCOM_ADDR_ERROR; | ||
} | ||
|
||
return OPAL_SUCCESS; | ||
} | ||
|
||
static int64_t ocmb_fake_scom_read(struct scom_controller *f, | ||
uint32_t chip_id __unused, | ||
uint64_t offset, uint64_t *val) | ||
{ | ||
const struct ocmb *o = f->private; | ||
const struct ocmb_range *r = NULL; | ||
|
||
r = find_range(o, offset); | ||
if (!r) { | ||
prerror("no matching address range!\n"); | ||
return OPAL_XSCOM_ADDR_ERROR; | ||
} | ||
|
||
|
||
switch (r->flags & ACCESS_SIZE_MASK) { | ||
case ACCESS_8B: | ||
if (offset & 0x7) | ||
return OPAL_XSCOM_ADDR_ERROR; | ||
*val = in_be64((void *) offset); | ||
break; | ||
|
||
case ACCESS_4B: | ||
if (offset & 0x3) | ||
return OPAL_XSCOM_ADDR_ERROR; | ||
*val = in_be32((void *) offset); | ||
break; | ||
default: | ||
prerror("bad flags? %llx\n", r->flags); | ||
return OPAL_XSCOM_ADDR_ERROR; | ||
} | ||
|
||
return OPAL_SUCCESS; | ||
} | ||
|
||
static bool ocmb_probe_one(struct dt_node *ocmb_node) | ||
{ | ||
uint64_t chip_id = dt_prop_get_u32(ocmb_node, "ibm,chip-id"); | ||
const struct dt_property *flags; | ||
int i = 0, num = 0; | ||
struct ocmb *ocmb; | ||
|
||
num = dt_count_addresses(ocmb_node); | ||
|
||
ocmb = zalloc(sizeof(*ocmb) + sizeof(*ocmb->ranges) * num); | ||
if (!ocmb) | ||
return false; | ||
|
||
ocmb->scom.private = ocmb; | ||
ocmb->scom.part_id = chip_id; | ||
ocmb->scom.write = ocmb_fake_scom_write; | ||
ocmb->scom.read = ocmb_fake_scom_read; | ||
ocmb->range_count = num; | ||
|
||
flags = dt_require_property(ocmb_node, "flags", sizeof(u64) * num); | ||
|
||
for (i = 0; i < num; i++) { | ||
uint64_t start, size; | ||
|
||
start = dt_get_address(ocmb_node, i, &size); | ||
|
||
ocmb->ranges[i].start = start; | ||
ocmb->ranges[i].end = start + size - 1; | ||
ocmb->ranges[i].flags = dt_property_get_u64(flags, i); | ||
|
||
prlog(PR_DEBUG, "Added range: %" PRIx64 " - [%llx - %llx]\n", | ||
chip_id, start, start + size - 1); | ||
} | ||
|
||
if (scom_register(&ocmb->scom)) | ||
prerror("error registienr fake socm\n"); | ||
|
||
dt_add_property(ocmb_node, "scom-controller", NULL, 0); | ||
|
||
prerror("XXX: Added scom controller for %s\n", ocmb_node->name); | ||
|
||
return true; | ||
} | ||
|
||
void ocmb_init(void) | ||
{ | ||
struct dt_node *dn; | ||
|
||
dt_for_each_compatible(dt_root, dn, "ibm,explorer") | ||
ocmb_probe_one(dn); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later | ||
/* | ||
* Open Capi Memory Buffer chip | ||
* | ||
* Copyright 2020 IBM Corp. | ||
*/ | ||
|
||
#ifndef __OCMB_H | ||
#define __OCMB_H | ||
|
||
extern void ocmb_init(void); | ||
|
||
#endif /* __OCMB_H */ |