xref: /aosp_15_r20/external/flashrom/atavia.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
1*0d6140beSAndroid Build Coastguard Worker /*
2*0d6140beSAndroid Build Coastguard Worker  * This file is part of the flashrom project.
3*0d6140beSAndroid Build Coastguard Worker  *
4*0d6140beSAndroid Build Coastguard Worker  * Copyright (C) 2010 Uwe Hermann <[email protected]>
5*0d6140beSAndroid Build Coastguard Worker  * Copyright (C) 2011 Jonathan Kollasch <[email protected]>
6*0d6140beSAndroid Build Coastguard Worker  * Copyright (C) 2012-2013 Stefan Tauner
7*0d6140beSAndroid Build Coastguard Worker  *
8*0d6140beSAndroid Build Coastguard Worker  * This program is free software; you can redistribute it and/or modify
9*0d6140beSAndroid Build Coastguard Worker  * it under the terms of the GNU General Public License as published by
10*0d6140beSAndroid Build Coastguard Worker  * the Free Software Foundation; either version 2 of the License, or
11*0d6140beSAndroid Build Coastguard Worker  * (at your option) any later version.
12*0d6140beSAndroid Build Coastguard Worker  *
13*0d6140beSAndroid Build Coastguard Worker  * This program is distributed in the hope that it will be useful,
14*0d6140beSAndroid Build Coastguard Worker  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15*0d6140beSAndroid Build Coastguard Worker  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*0d6140beSAndroid Build Coastguard Worker  * GNU General Public License for more details.
17*0d6140beSAndroid Build Coastguard Worker  */
18*0d6140beSAndroid Build Coastguard Worker 
19*0d6140beSAndroid Build Coastguard Worker #include <stdlib.h>
20*0d6140beSAndroid Build Coastguard Worker #include <string.h>
21*0d6140beSAndroid Build Coastguard Worker #include "flash.h"
22*0d6140beSAndroid Build Coastguard Worker #include "programmer.h"
23*0d6140beSAndroid Build Coastguard Worker #include "platform/pci.h"
24*0d6140beSAndroid Build Coastguard Worker 
25*0d6140beSAndroid Build Coastguard Worker #define PCI_VENDOR_ID_VIA	0x1106
26*0d6140beSAndroid Build Coastguard Worker 
27*0d6140beSAndroid Build Coastguard Worker #define VIA_MAX_RETRIES		300
28*0d6140beSAndroid Build Coastguard Worker 
29*0d6140beSAndroid Build Coastguard Worker #define BROM_ADDR		0x60
30*0d6140beSAndroid Build Coastguard Worker 
31*0d6140beSAndroid Build Coastguard Worker #define BROM_DATA		0x64
32*0d6140beSAndroid Build Coastguard Worker 
33*0d6140beSAndroid Build Coastguard Worker #define BROM_ACCESS		0x68
34*0d6140beSAndroid Build Coastguard Worker #define BROM_TRIGGER		0x80
35*0d6140beSAndroid Build Coastguard Worker #define BROM_WRITE		0x40
36*0d6140beSAndroid Build Coastguard Worker #define BROM_SIZE_MASK		0x30
37*0d6140beSAndroid Build Coastguard Worker #define BROM_SIZE_64K		0x00
38*0d6140beSAndroid Build Coastguard Worker #define BROM_SIZE_32K		0x10
39*0d6140beSAndroid Build Coastguard Worker #define BROM_SIZE_16K		0x20
40*0d6140beSAndroid Build Coastguard Worker #define BROM_SIZE_0K		0x30
41*0d6140beSAndroid Build Coastguard Worker #define BROM_BYTE_ENABLE_MASK	0x0f
42*0d6140beSAndroid Build Coastguard Worker 
43*0d6140beSAndroid Build Coastguard Worker #define BROM_STATUS		0x69
44*0d6140beSAndroid Build Coastguard Worker #define BROM_ERROR_STATUS	0x80
45*0d6140beSAndroid Build Coastguard Worker 
46*0d6140beSAndroid Build Coastguard Worker /* Select the byte we want to access. This is done by clearing the bit corresponding to the byte we want to
47*0d6140beSAndroid Build Coastguard Worker  * access, leaving the others set (yes, really). */
48*0d6140beSAndroid Build Coastguard Worker #define ENABLE_BYTE(address)	((~(1 << ((address) & 3))) & BROM_BYTE_ENABLE_MASK)
49*0d6140beSAndroid Build Coastguard Worker #define BYTE_OFFSET(address)	(((address) & 3) * 8)
50*0d6140beSAndroid Build Coastguard Worker 
51*0d6140beSAndroid Build Coastguard Worker static const struct dev_entry ata_via[] = {
52*0d6140beSAndroid Build Coastguard Worker 	{PCI_VENDOR_ID_VIA, 0x3249, DEP, "VIA", "VT6421A"},
53*0d6140beSAndroid Build Coastguard Worker 
54*0d6140beSAndroid Build Coastguard Worker 	{0},
55*0d6140beSAndroid Build Coastguard Worker };
56*0d6140beSAndroid Build Coastguard Worker 
57*0d6140beSAndroid Build Coastguard Worker static void *atavia_offset = NULL;
58*0d6140beSAndroid Build Coastguard Worker static struct pci_dev *dev = NULL;
59*0d6140beSAndroid Build Coastguard Worker 
atavia_prettyprint_access(uint8_t access)60*0d6140beSAndroid Build Coastguard Worker static void atavia_prettyprint_access(uint8_t access)
61*0d6140beSAndroid Build Coastguard Worker {
62*0d6140beSAndroid Build Coastguard Worker 	uint8_t bmask = access & BROM_BYTE_ENABLE_MASK;
63*0d6140beSAndroid Build Coastguard Worker 	uint8_t size = access & BROM_SIZE_MASK;
64*0d6140beSAndroid Build Coastguard Worker 
65*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("Accessing byte(s):%s%s%s%s\n",
66*0d6140beSAndroid Build Coastguard Worker 		  ((bmask & (1<<3)) == 0) ? " 3" : "",
67*0d6140beSAndroid Build Coastguard Worker 		  ((bmask & (1<<2)) == 0) ? " 2" : "",
68*0d6140beSAndroid Build Coastguard Worker 		  ((bmask & (1<<1)) == 0) ? " 1" : "",
69*0d6140beSAndroid Build Coastguard Worker 		  ((bmask & (1<<0)) == 0) ? " 0" : "");
70*0d6140beSAndroid Build Coastguard Worker 	if (size == BROM_SIZE_0K) {
71*0d6140beSAndroid Build Coastguard Worker 		msg_pspew("No ROM device found.\n");
72*0d6140beSAndroid Build Coastguard Worker 	} else
73*0d6140beSAndroid Build Coastguard Worker 		msg_pspew("ROM device with %s kB attached.\n",
74*0d6140beSAndroid Build Coastguard Worker 			  (size == BROM_SIZE_64K) ? ">=64" :
75*0d6140beSAndroid Build Coastguard Worker 			  (size == BROM_SIZE_32K) ? "32" : "16");
76*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("Access is a %s.\n", (access & BROM_WRITE) ? "write" : "read");
77*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("Device is %s.\n", (access & BROM_TRIGGER) ? "busy" : "ready");
78*0d6140beSAndroid Build Coastguard Worker }
79*0d6140beSAndroid Build Coastguard Worker 
atavia_ready(struct pci_dev * pcidev_dev)80*0d6140beSAndroid Build Coastguard Worker static bool atavia_ready(struct pci_dev *pcidev_dev)
81*0d6140beSAndroid Build Coastguard Worker {
82*0d6140beSAndroid Build Coastguard Worker 	int try;
83*0d6140beSAndroid Build Coastguard Worker 	uint8_t access, status;
84*0d6140beSAndroid Build Coastguard Worker 	bool ready = false;
85*0d6140beSAndroid Build Coastguard Worker 
86*0d6140beSAndroid Build Coastguard Worker 	for (try = 0; try < VIA_MAX_RETRIES; try++) {
87*0d6140beSAndroid Build Coastguard Worker 		access = pci_read_byte(pcidev_dev, BROM_ACCESS);
88*0d6140beSAndroid Build Coastguard Worker 		status = pci_read_byte(pcidev_dev, BROM_STATUS);
89*0d6140beSAndroid Build Coastguard Worker 		if (((access & BROM_TRIGGER) == 0) && (status & BROM_ERROR_STATUS) == 0) {
90*0d6140beSAndroid Build Coastguard Worker 			ready = true;
91*0d6140beSAndroid Build Coastguard Worker 			break;
92*0d6140beSAndroid Build Coastguard Worker 		} else {
93*0d6140beSAndroid Build Coastguard Worker 			default_delay(1);
94*0d6140beSAndroid Build Coastguard Worker 			continue;
95*0d6140beSAndroid Build Coastguard Worker 		}
96*0d6140beSAndroid Build Coastguard Worker 	}
97*0d6140beSAndroid Build Coastguard Worker 
98*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg2("\n%s: %s after %d tries (access=0x%02x, status=0x%02x)\n",
99*0d6140beSAndroid Build Coastguard Worker 		  __func__, ready ? "succeeded" : "failed", try, access, status);
100*0d6140beSAndroid Build Coastguard Worker 	atavia_prettyprint_access(access);
101*0d6140beSAndroid Build Coastguard Worker 	return ready;
102*0d6140beSAndroid Build Coastguard Worker }
103*0d6140beSAndroid Build Coastguard Worker 
atavia_map(const char * descr,uintptr_t phys_addr,size_t len)104*0d6140beSAndroid Build Coastguard Worker static void *atavia_map(const char *descr, uintptr_t phys_addr, size_t len)
105*0d6140beSAndroid Build Coastguard Worker {
106*0d6140beSAndroid Build Coastguard Worker 	return (atavia_offset != 0) ? atavia_offset : (void *)phys_addr;
107*0d6140beSAndroid Build Coastguard Worker }
108*0d6140beSAndroid Build Coastguard Worker 
atavia_chip_writeb(const struct flashctx * flash,uint8_t val,const chipaddr addr)109*0d6140beSAndroid Build Coastguard Worker static void atavia_chip_writeb(const struct flashctx *flash, uint8_t val, const chipaddr addr)
110*0d6140beSAndroid Build Coastguard Worker {
111*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("%s: 0x%02x to 0x%*" PRIxPTR ".\n", __func__, val, PRIxPTR_WIDTH, addr);
112*0d6140beSAndroid Build Coastguard Worker 	pci_write_long(dev, BROM_ADDR, (addr & ~3));
113*0d6140beSAndroid Build Coastguard Worker 	pci_write_long(dev, BROM_DATA, val << BYTE_OFFSET(addr));
114*0d6140beSAndroid Build Coastguard Worker 	pci_write_byte(dev, BROM_ACCESS, BROM_TRIGGER | BROM_WRITE | ENABLE_BYTE(addr));
115*0d6140beSAndroid Build Coastguard Worker 
116*0d6140beSAndroid Build Coastguard Worker 	if (!atavia_ready(dev)) {
117*0d6140beSAndroid Build Coastguard Worker 		msg_perr("not ready after write\n");
118*0d6140beSAndroid Build Coastguard Worker 	}
119*0d6140beSAndroid Build Coastguard Worker }
120*0d6140beSAndroid Build Coastguard Worker 
atavia_chip_readb(const struct flashctx * flash,const chipaddr addr)121*0d6140beSAndroid Build Coastguard Worker static uint8_t atavia_chip_readb(const struct flashctx *flash, const chipaddr addr)
122*0d6140beSAndroid Build Coastguard Worker {
123*0d6140beSAndroid Build Coastguard Worker 	pci_write_long(dev, BROM_ADDR, (addr & ~3));
124*0d6140beSAndroid Build Coastguard Worker 	pci_write_byte(dev, BROM_ACCESS, BROM_TRIGGER | ENABLE_BYTE(addr));
125*0d6140beSAndroid Build Coastguard Worker 
126*0d6140beSAndroid Build Coastguard Worker 	if (!atavia_ready(dev)) {
127*0d6140beSAndroid Build Coastguard Worker 		msg_perr("not ready after read\n");
128*0d6140beSAndroid Build Coastguard Worker 	}
129*0d6140beSAndroid Build Coastguard Worker 
130*0d6140beSAndroid Build Coastguard Worker 	uint8_t val = (pci_read_long(dev, BROM_DATA) >> BYTE_OFFSET(addr)) & 0xff;
131*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("%s: 0x%02x from 0x%*" PRIxPTR ".\n", __func__, val, PRIxPTR_WIDTH, addr);
132*0d6140beSAndroid Build Coastguard Worker 	return val;
133*0d6140beSAndroid Build Coastguard Worker }
134*0d6140beSAndroid Build Coastguard Worker 
135*0d6140beSAndroid Build Coastguard Worker static const struct par_master lpc_master_atavia = {
136*0d6140beSAndroid Build Coastguard Worker 	.map_flash_region	= atavia_map,
137*0d6140beSAndroid Build Coastguard Worker 	.chip_readb	= atavia_chip_readb,
138*0d6140beSAndroid Build Coastguard Worker 	.chip_writeb	= atavia_chip_writeb,
139*0d6140beSAndroid Build Coastguard Worker };
140*0d6140beSAndroid Build Coastguard Worker 
atavia_init(const struct programmer_cfg * cfg)141*0d6140beSAndroid Build Coastguard Worker static int atavia_init(const struct programmer_cfg *cfg)
142*0d6140beSAndroid Build Coastguard Worker {
143*0d6140beSAndroid Build Coastguard Worker 	char *arg = extract_programmer_param_str(cfg, "offset");
144*0d6140beSAndroid Build Coastguard Worker 	if (arg) {
145*0d6140beSAndroid Build Coastguard Worker 		if (strlen(arg) == 0) {
146*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Missing argument for offset.\n");
147*0d6140beSAndroid Build Coastguard Worker 			free(arg);
148*0d6140beSAndroid Build Coastguard Worker 			return ERROR_FLASHROM_FATAL;
149*0d6140beSAndroid Build Coastguard Worker 		}
150*0d6140beSAndroid Build Coastguard Worker 		char *endptr;
151*0d6140beSAndroid Build Coastguard Worker 		atavia_offset = (void *)strtoul(arg, &endptr, 0);
152*0d6140beSAndroid Build Coastguard Worker 		if (*endptr) {
153*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: Invalid offset specified: \"%s\".\n", arg);
154*0d6140beSAndroid Build Coastguard Worker 			free(arg);
155*0d6140beSAndroid Build Coastguard Worker 			return ERROR_FLASHROM_FATAL;
156*0d6140beSAndroid Build Coastguard Worker 		}
157*0d6140beSAndroid Build Coastguard Worker 		msg_pinfo("Mapping addresses to base %p.\n", atavia_offset);
158*0d6140beSAndroid Build Coastguard Worker 	}
159*0d6140beSAndroid Build Coastguard Worker 	free(arg);
160*0d6140beSAndroid Build Coastguard Worker 
161*0d6140beSAndroid Build Coastguard Worker 	dev = pcidev_init(cfg, ata_via, PCI_ROM_ADDRESS); /* Actually no BAR setup needed at all. */
162*0d6140beSAndroid Build Coastguard Worker 	if (!dev)
163*0d6140beSAndroid Build Coastguard Worker 		return 1;
164*0d6140beSAndroid Build Coastguard Worker 
165*0d6140beSAndroid Build Coastguard Worker 	/* Test if a flash chip is attached. */
166*0d6140beSAndroid Build Coastguard Worker 	pci_write_long(dev, PCI_ROM_ADDRESS, (uint32_t)PCI_ROM_ADDRESS_MASK);
167*0d6140beSAndroid Build Coastguard Worker 	default_delay(90);
168*0d6140beSAndroid Build Coastguard Worker 	uint32_t base = pci_read_long(dev, PCI_ROM_ADDRESS);
169*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg2("BROM base=0x%08"PRIx32"\n", base);
170*0d6140beSAndroid Build Coastguard Worker 	if ((base & PCI_ROM_ADDRESS_MASK) == 0) {
171*0d6140beSAndroid Build Coastguard Worker 		msg_pwarn("Controller thinks there is no ROM attached.\n");
172*0d6140beSAndroid Build Coastguard Worker 	}
173*0d6140beSAndroid Build Coastguard Worker 
174*0d6140beSAndroid Build Coastguard Worker 	if (!atavia_ready(dev)) {
175*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Controller not ready.\n");
176*0d6140beSAndroid Build Coastguard Worker 		return 1;
177*0d6140beSAndroid Build Coastguard Worker 	}
178*0d6140beSAndroid Build Coastguard Worker 
179*0d6140beSAndroid Build Coastguard Worker 	return register_par_master(&lpc_master_atavia, BUS_LPC, NULL);
180*0d6140beSAndroid Build Coastguard Worker }
181*0d6140beSAndroid Build Coastguard Worker 
182*0d6140beSAndroid Build Coastguard Worker const struct programmer_entry programmer_atavia = {
183*0d6140beSAndroid Build Coastguard Worker 	.name			= "atavia",
184*0d6140beSAndroid Build Coastguard Worker 	.type			= PCI,
185*0d6140beSAndroid Build Coastguard Worker 	.devs.dev		= ata_via,
186*0d6140beSAndroid Build Coastguard Worker 	.init			= atavia_init,
187*0d6140beSAndroid Build Coastguard Worker };
188