aboutsummaryrefslogtreecommitdiff
path: root/hw/nx.c
blob: 8f427173caf000b4b4d661ff154f6225a342bf9c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/* 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 <xscom.h>
#include <io.h>
#include <cpu.h>
#include <nx.h>

#define NX_P7_RNG_BAR		XSCOM_SAT(0x1, 0x2, 0x0c)
#define   NX_P7_RNG_BAR_ADDR_MASK	PPC_BITMASK(18, 51)
#define   NX_P7_RNG_BAR_ADDR_LSH	PPC_BITLSHIFT(51)
#define   NX_P7_RNG_BAR_SIZE_MASK	PPC_BITMASK(53, 55)
#define   NX_P7_RNG_BAR_SIZE_LSH	PPC_BITLSHIFT(55)
#define   NX_P7_RNG_BAR_ENABLE		PPC_BIT(52)

#define NX_P8_RNG_BAR		XSCOM_SAT(0xc, 0x2, 0x0d)
#define   NX_P8_RNG_BAR_ADDR_MASK	PPC_BITMASK(14, 51)
#define   NX_P8_RNG_BAR_ADDR_LSH	PPC_BITLSHIFT(51)
#define   NX_P8_RNG_BAR_SIZE_MASK	PPC_BITMASK(53, 55)
#define   NX_P8_RNG_BAR_SIZE_LSH	PPC_BITLSHIFT(55)
#define   NX_P8_RNG_BAR_ENABLE		PPC_BIT(52)

#define NX_P7_RNG_CFG		XSCOM_SAT(0x1, 0x2, 0x12)
#define   NX_P7_RNG_CFG_ENABLE		PPC_BIT(63)
#define NX_P8_RNG_CFG		XSCOM_SAT(0xc, 0x2, 0x12)
#define   NX_P8_RNG_CFG_ENABLE		PPC_BIT(63)

static void nx_create_node(struct dt_node *node)
{
	u64 bar, cfg;
	u64 xbar, xcfg;
	u32 pb_base;
	u32 gcid;
	u64 rng_addr, rng_len, len;
	struct dt_node *rng;
	int rc;

	gcid = dt_get_chip_id(node);
	pb_base = dt_get_address(node, 0, NULL);

	if (dt_node_is_compatible(node, "ibm,power7-nx")) {
		xbar = pb_base + NX_P7_RNG_BAR;
		xcfg = pb_base + NX_P7_RNG_CFG;
	} else if (dt_node_is_compatible(node, "ibm,power8-nx")) {
		xbar = pb_base + NX_P8_RNG_BAR;
		xcfg = pb_base + NX_P8_RNG_CFG;
	} else {
		prerror("NX%d: Unknown NX type!\n", gcid);
		return;
	}

	rc = xscom_read(gcid, xbar, &bar); /* Get RNG BAR */
	if (rc)
		return;	/* Hope xscom always prints error message */

	rc = xscom_read(gcid, xcfg, &cfg); /* Get RNG CFG */
	if (rc)
		return;

	/*
	 * We use the P8 BAR constants. The layout of the BAR is the
	 * same, with more bits at the top of P8 which are hard wired to
	 * 0 on P7. We also mask in-place rather than using GETFIELD
	 * for the base address as we happen to *know* that it's properly
	 * aligned in the register.
	 *
	 * FIXME? Always assusme BAR gets a valid address from FSP
	 */
	rng_addr = bar & NX_P8_RNG_BAR_ADDR_MASK;
	len  = GETFIELD(NX_P8_RNG_BAR_SIZE, bar);
	if (len > 4) {
		prerror("NX%d: Corrupted bar size %lld\n", gcid, len);
		return;
	}
	rng_len = (u64[]){  0x1000,         /* 4K */
			    0x10000,        /* 64K */
			    0x400000000,    /* 16G*/
			    0x100000,       /* 1M */
			    0x1000000       /* 16M */} [len];


	printf("NX%d: RNG BAR set to 0x%016llx..0x%016llx\n",
	       gcid, rng_addr, rng_addr + rng_len - 1);

	/* RNG must be enabled before MMIO is enabled */
	rc = xscom_write(gcid, xcfg, cfg | NX_P8_RNG_CFG_ENABLE);
	if (rc)
		return;

	/* The BAR needs to be enabled too */
	rc = xscom_write(gcid, xbar, bar | NX_P8_RNG_BAR_ENABLE);
	if (rc)
		return;
	rng = dt_new_addr(dt_root, "hwrng", rng_addr);
	if (!rng)
		return;

	dt_add_property_strings(rng, "compatible", "ibm,power-rng");
	dt_add_property_cells(rng, "reg", hi32(rng_addr), lo32(rng_addr),
			hi32(rng_len), lo32(rng_len));
	dt_add_property_cells(rng, "ibm,chip-id", gcid);
}

/* Create nodes for MMIO accesible components in NX (only RNG) */
void nx_init(void)
{
	struct dt_node *node;

	dt_for_each_compatible(dt_root, node, "ibm,power-nx")
		nx_create_node(node);
}