xref: /aosp_15_r20/external/flashrom/satamv.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
1 /*
2  * This file is part of the flashrom project.
3  *
4  * Copyright (C) 2010,2011 Carl-Daniel Hailfinger
5  * Written by Carl-Daniel Hailfinger for Angelbird Ltd.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; version 2 of the License.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  */
16 
17 /* Datasheets are not public (yet?) */
18 
19 #include <stdlib.h>
20 #include "flash.h"
21 #include "programmer.h"
22 #include "hwaccess_x86_io.h"
23 #include "hwaccess_physmap.h"
24 #include "platform/pci.h"
25 
26 struct satamv_data {
27 	uint8_t *bar;
28 	uint16_t iobar;
29 };
30 
31 static const struct dev_entry satas_mv[] = {
32 	/* 88SX6041 and 88SX6042 are the same according to the datasheet. */
33 	{0x11ab, 0x7042, OK, "Marvell", "88SX7042 PCI-e 4-port SATA-II"},
34 
35 	{0},
36 };
37 
38 #define NVRAM_PARAM			0x1045c
39 #define FLASH_PARAM			0x1046c
40 #define EXPANSION_ROM_BAR_CONTROL	0x00d2c
41 #define PCI_BAR2_CONTROL		0x00c08
42 #define GPIO_PORT_CONTROL		0x104f0
43 
44 /* BAR2 (MEM) can map NVRAM and flash. We set it to flash in the init function.
45  * If BAR2 is disabled, it still can be accessed indirectly via BAR1 (I/O).
46  * This code only supports indirect accesses for now.
47  */
48 
49 /* Indirect access to via the I/O BAR1. */
satamv_indirect_chip_writeb(uint8_t val,chipaddr addr,uint16_t iobar)50 static void satamv_indirect_chip_writeb(uint8_t val, chipaddr addr, uint16_t iobar)
51 {
52 	/* 0x80000000 selects BAR2 for remapping. */
53 	OUTL(((uint32_t)addr | 0x80000000) & 0xfffffffc, iobar);
54 	OUTB(val, iobar + 0x80 + (addr & 0x3));
55 }
56 
57 /* Indirect access to via the I/O BAR1. */
satamv_indirect_chip_readb(const chipaddr addr,uint16_t iobar)58 static uint8_t satamv_indirect_chip_readb(const chipaddr addr, uint16_t iobar)
59 {
60 	/* 0x80000000 selects BAR2 for remapping. */
61 	OUTL(((uint32_t)addr | 0x80000000) & 0xfffffffc, iobar);
62 	return INB(iobar + 0x80 + (addr & 0x3));
63 }
64 
65 /* FIXME: Prefer direct access to BAR2 if BAR2 is active. */
satamv_chip_writeb(const struct flashctx * flash,uint8_t val,chipaddr addr)66 static void satamv_chip_writeb(const struct flashctx *flash, uint8_t val,
67 			       chipaddr addr)
68 {
69 	const struct satamv_data *data = flash->mst->par.data;
70 
71 	satamv_indirect_chip_writeb(val, addr, data->iobar);
72 }
73 
74 /* FIXME: Prefer direct access to BAR2 if BAR2 is active. */
satamv_chip_readb(const struct flashctx * flash,const chipaddr addr)75 static uint8_t satamv_chip_readb(const struct flashctx *flash,
76 				 const chipaddr addr)
77 {
78 	const struct satamv_data *data = flash->mst->par.data;
79 
80 	return satamv_indirect_chip_readb(addr, data->iobar);
81 }
82 
satamv_shutdown(void * par_data)83 static int satamv_shutdown(void *par_data)
84 {
85 	free(par_data);
86 	return 0;
87 }
88 
89 static const struct par_master par_master_satamv = {
90 	.chip_readb	= satamv_chip_readb,
91 	.chip_writeb	= satamv_chip_writeb,
92 	.shutdown	= satamv_shutdown,
93 };
94 
95 /*
96  * Random notes:
97  * FCE#		Flash Chip Enable
98  * FWE#		Flash Write Enable
99  * FOE#		Flash Output Enable
100  * FALE[1:0]	Flash Address Latch Enable
101  * FAD[7:0]	Flash Multiplexed Address/Data Bus
102  * FA[2:0]	Flash Address Low
103  *
104  * GPIO[15,2]	GPIO Port Mode
105  * GPIO[4:3]	Flash Size
106  *
107  * 0xd2c	Expansion ROM BAR Control
108  * 0xc08	PCI BAR2 (Flash/NVRAM) Control
109  * 0x1046c	Flash Parameters
110  */
satamv_init(const struct programmer_cfg * cfg)111 static int satamv_init(const struct programmer_cfg *cfg)
112 {
113 	struct pci_dev *dev = NULL;
114 	uintptr_t addr;
115 	uint32_t tmp;
116 	uint16_t iobar;
117 	uint8_t *bar;
118 
119 	if (rget_io_perms())
120 		return 1;
121 
122 	/* BAR0 has all internal registers memory mapped. */
123 	dev = pcidev_init(cfg, satas_mv, PCI_BASE_ADDRESS_0);
124 	if (!dev)
125 		return 1;
126 
127 	addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0);
128 	if (!addr)
129 		return 1;
130 
131 	bar = rphysmap("Marvell 88SX7042 registers", addr, 0x20000);
132 	if (bar == ERROR_PTR)
133 		return 1;
134 
135 	tmp = pci_mmio_readl(bar + FLASH_PARAM);
136 	msg_pspew("Flash Parameters:\n");
137 	msg_pspew("TurnOff=0x%01"PRIx32"\n", (tmp >> 0) & 0x7);
138 	msg_pspew("Acc2First=0x%01"PRIx32"\n", (tmp >> 3) & 0xf);
139 	msg_pspew("Acc2Next=0x%01"PRIx32"\n", (tmp >> 7) & 0xf);
140 	msg_pspew("ALE2Wr=0x%01"PRIx32"\n", (tmp >> 11) & 0x7);
141 	msg_pspew("WrLow=0x%01"PRIx32"\n", (tmp >> 14) & 0x7);
142 	msg_pspew("WrHigh=0x%01"PRIx32"\n", (tmp >> 17) & 0x7);
143 	msg_pspew("Reserved[21:20]=0x%01"PRIx32"\n", (tmp >> 20) & 0x3);
144 	msg_pspew("TurnOffExt=0x%01"PRIx32"\n", (tmp >> 22) & 0x1);
145 	msg_pspew("Acc2FirstExt=0x%01"PRIx32"\n", (tmp >> 23) & 0x1);
146 	msg_pspew("Acc2NextExt=0x%01"PRIx32"\n", (tmp >> 24) & 0x1);
147 	msg_pspew("ALE2WrExt=0x%01"PRIx32"\n", (tmp >> 25) & 0x1);
148 	msg_pspew("WrLowExt=0x%01"PRIx32"\n", (tmp >> 26) & 0x1);
149 	msg_pspew("WrHighExt=0x%01"PRIx32"\n", (tmp >> 27) & 0x1);
150 	msg_pspew("Reserved[31:28]=0x%01"PRIx32"\n", (tmp >> 28) & 0xf);
151 
152 	tmp = pci_mmio_readl(bar + EXPANSION_ROM_BAR_CONTROL);
153 	msg_pspew("Expansion ROM BAR Control:\n");
154 	msg_pspew("ExpROMSz=0x%01"PRIx32"\n", (tmp >> 19) & 0x7);
155 
156 	/* Enable BAR2 mapping to flash */
157 	tmp = pci_mmio_readl(bar + PCI_BAR2_CONTROL);
158 	msg_pspew("PCI BAR2 (Flash/NVRAM) Control:\n");
159 	msg_pspew("Bar2En=0x%01"PRIx32"\n", (tmp >> 0) & 0x1);
160 	msg_pspew("BAR2TransAttr=0x%01"PRIx32"\n", (tmp >> 1) & 0x1f);
161 	msg_pspew("BAR2Sz=0x%01"PRIx32"\n", (tmp >> 19) & 0x7);
162 	tmp &= 0xffffffc0;
163 	tmp |= 0x0000001f;
164 	pci_rmmio_writel(tmp, bar + PCI_BAR2_CONTROL);
165 
166 	/* Enable flash: GPIO Port Control Register 0x104f0 */
167 	tmp = pci_mmio_readl(bar + GPIO_PORT_CONTROL);
168 	msg_pspew("GPIOPortMode=0x%01"PRIx32"\n", (tmp >> 0) & 0x3);
169 	if (((tmp >> 0) & 0x3) != 0x2)
170 		msg_pinfo("Warning! Either the straps are incorrect or you "
171 			  "have no flash or someone overwrote the strap "
172 			  "values!\n");
173 	tmp &= 0xfffffffc;
174 	tmp |= 0x2;
175 	pci_rmmio_writel(tmp, bar + GPIO_PORT_CONTROL);
176 
177 	/* Get I/O BAR location. */
178 	addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_2);
179 	if (!addr)
180 		return 1;
181 
182 	/* Truncate to reachable range.
183 	 * FIXME: Check if the I/O BAR is actually reachable.
184 	 * This is an arch specific check.
185 	 */
186 	iobar = addr & 0xffff;
187 	msg_pspew("Activating I/O BAR at 0x%04x\n", iobar);
188 
189 	struct satamv_data *data = calloc(1, sizeof(*data));
190 	if (!data) {
191 		msg_perr("Unable to allocate space for PAR master data\n");
192 		return 1;
193 	}
194 	data->bar = bar;
195 	data->iobar = iobar;
196 
197 	/* 512 kByte with two 8-bit latches, and
198 	 * 4 MByte with additional 3-bit latch. */
199 	max_rom_decode.parallel = 4 * 1024 * 1024;
200 	return register_par_master(&par_master_satamv, BUS_PARALLEL, data);
201 }
202 
203 const struct programmer_entry programmer_satamv = {
204 	.name			= "satamv",
205 	.type			= PCI,
206 	.devs.dev		= satas_mv,
207 	.init			= satamv_init,
208 };
209