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) 2023 Alex Badea <[email protected]>
5*0d6140beSAndroid Build Coastguard Worker *
6*0d6140beSAndroid Build Coastguard Worker * This program is free software; you can redistribute it and/or modify
7*0d6140beSAndroid Build Coastguard Worker * it under the terms of the GNU General Public License as published by
8*0d6140beSAndroid Build Coastguard Worker * the Free Software Foundation; either version 2 of the License, or
9*0d6140beSAndroid Build Coastguard Worker * (at your option) any later version.
10*0d6140beSAndroid Build Coastguard Worker *
11*0d6140beSAndroid Build Coastguard Worker * This program is distributed in the hope that it will be useful,
12*0d6140beSAndroid Build Coastguard Worker * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*0d6140beSAndroid Build Coastguard Worker * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14*0d6140beSAndroid Build Coastguard Worker * GNU General Public License for more details.
15*0d6140beSAndroid Build Coastguard Worker */
16*0d6140beSAndroid Build Coastguard Worker
17*0d6140beSAndroid Build Coastguard Worker #include <stdlib.h>
18*0d6140beSAndroid Build Coastguard Worker #include "programmer.h"
19*0d6140beSAndroid Build Coastguard Worker #include "platform/pci.h"
20*0d6140beSAndroid Build Coastguard Worker
21*0d6140beSAndroid Build Coastguard Worker #define PCI_VENDOR_ID_ASMEDIA 0x1b21
22*0d6140beSAndroid Build Coastguard Worker
23*0d6140beSAndroid Build Coastguard Worker #define ASM106X_REG_DATA 0xf0
24*0d6140beSAndroid Build Coastguard Worker #define ASM106X_REG_CTRL 0xf4
25*0d6140beSAndroid Build Coastguard Worker #define ASM106X_CTRL_RUN 0x20 /* SPI master is running */
26*0d6140beSAndroid Build Coastguard Worker #define ASM106X_CTRL_CSN 0x10 /* CS_n pin output */
27*0d6140beSAndroid Build Coastguard Worker #define ASM106X_CTRL_WRITE 0x08 /* 0=read, 1=write */
28*0d6140beSAndroid Build Coastguard Worker #define ASM106X_CTRL_MASK 0xc0 /* unknown, untouched */
29*0d6140beSAndroid Build Coastguard Worker
30*0d6140beSAndroid Build Coastguard Worker struct asm106x_data {
31*0d6140beSAndroid Build Coastguard Worker struct pci_dev *pci;
32*0d6140beSAndroid Build Coastguard Worker };
33*0d6140beSAndroid Build Coastguard Worker
34*0d6140beSAndroid Build Coastguard Worker static const struct dev_entry asm106x_devs[] = {
35*0d6140beSAndroid Build Coastguard Worker {PCI_VENDOR_ID_ASMEDIA, 0x0612, OK, "ASMedia", "ASM106x"},
36*0d6140beSAndroid Build Coastguard Worker
37*0d6140beSAndroid Build Coastguard Worker {0},
38*0d6140beSAndroid Build Coastguard Worker };
39*0d6140beSAndroid Build Coastguard Worker
asm106x_wait_ready(struct pci_dev * pci,uint8_t * pval)40*0d6140beSAndroid Build Coastguard Worker static int asm106x_wait_ready(struct pci_dev *pci, uint8_t *pval)
41*0d6140beSAndroid Build Coastguard Worker {
42*0d6140beSAndroid Build Coastguard Worker unsigned int timeout = 100;
43*0d6140beSAndroid Build Coastguard Worker uint8_t val;
44*0d6140beSAndroid Build Coastguard Worker
45*0d6140beSAndroid Build Coastguard Worker while (timeout) {
46*0d6140beSAndroid Build Coastguard Worker val = pci_read_byte(pci, ASM106X_REG_CTRL);
47*0d6140beSAndroid Build Coastguard Worker msg_pdbg2("asm106x status %#02"PRIx8" tries %d\n", val, timeout);
48*0d6140beSAndroid Build Coastguard Worker if (!(val & ASM106X_CTRL_RUN)) {
49*0d6140beSAndroid Build Coastguard Worker if (pval)
50*0d6140beSAndroid Build Coastguard Worker *pval = val;
51*0d6140beSAndroid Build Coastguard Worker return 0;
52*0d6140beSAndroid Build Coastguard Worker }
53*0d6140beSAndroid Build Coastguard Worker default_delay(10);
54*0d6140beSAndroid Build Coastguard Worker timeout--;
55*0d6140beSAndroid Build Coastguard Worker }
56*0d6140beSAndroid Build Coastguard Worker
57*0d6140beSAndroid Build Coastguard Worker msg_pdbg("asm106x timed out, ctrl %#02"PRIx8"\n", val);
58*0d6140beSAndroid Build Coastguard Worker return 1;
59*0d6140beSAndroid Build Coastguard Worker }
60*0d6140beSAndroid Build Coastguard Worker
61*0d6140beSAndroid Build Coastguard Worker
asm106x_command(const struct flashctx * flash,unsigned int writecnt,unsigned int readcnt,const unsigned char * writearr,unsigned char * readarr)62*0d6140beSAndroid Build Coastguard Worker static int asm106x_command(const struct flashctx *flash,
63*0d6140beSAndroid Build Coastguard Worker unsigned int writecnt, unsigned int readcnt,
64*0d6140beSAndroid Build Coastguard Worker const unsigned char *writearr, unsigned char *readarr)
65*0d6140beSAndroid Build Coastguard Worker {
66*0d6140beSAndroid Build Coastguard Worker struct asm106x_data *data = flash->mst->spi.data;
67*0d6140beSAndroid Build Coastguard Worker uint8_t ctrl;
68*0d6140beSAndroid Build Coastguard Worker int rv = 1;
69*0d6140beSAndroid Build Coastguard Worker
70*0d6140beSAndroid Build Coastguard Worker msg_pdbg2("asm106x command: wr %d rd %d\n", writecnt, readcnt);
71*0d6140beSAndroid Build Coastguard Worker if (asm106x_wait_ready(data->pci, &ctrl))
72*0d6140beSAndroid Build Coastguard Worker return 1;
73*0d6140beSAndroid Build Coastguard Worker ctrl &= ASM106X_CTRL_MASK;
74*0d6140beSAndroid Build Coastguard Worker
75*0d6140beSAndroid Build Coastguard Worker while (writecnt) {
76*0d6140beSAndroid Build Coastguard Worker const unsigned int chunk = min(writecnt, 4);
77*0d6140beSAndroid Build Coastguard Worker uint32_t val = 0;
78*0d6140beSAndroid Build Coastguard Worker
79*0d6140beSAndroid Build Coastguard Worker for (int k = chunk-1; k >= 0; k--)
80*0d6140beSAndroid Build Coastguard Worker val = (val << 8) | writearr[k];
81*0d6140beSAndroid Build Coastguard Worker msg_pdbg2("asm106x write %#08"PRIx32" chunk %u\n", val, chunk);
82*0d6140beSAndroid Build Coastguard Worker pci_write_long(data->pci, ASM106X_REG_DATA, val);
83*0d6140beSAndroid Build Coastguard Worker pci_write_byte(data->pci, ASM106X_REG_CTRL,
84*0d6140beSAndroid Build Coastguard Worker ctrl | ASM106X_CTRL_RUN | ASM106X_CTRL_WRITE | chunk);
85*0d6140beSAndroid Build Coastguard Worker if (asm106x_wait_ready(data->pci, NULL))
86*0d6140beSAndroid Build Coastguard Worker goto out;
87*0d6140beSAndroid Build Coastguard Worker writecnt -= chunk;
88*0d6140beSAndroid Build Coastguard Worker writearr += chunk;
89*0d6140beSAndroid Build Coastguard Worker }
90*0d6140beSAndroid Build Coastguard Worker while (readcnt) {
91*0d6140beSAndroid Build Coastguard Worker const unsigned int chunk = min(readcnt, 4);
92*0d6140beSAndroid Build Coastguard Worker
93*0d6140beSAndroid Build Coastguard Worker pci_write_byte(data->pci, ASM106X_REG_CTRL,
94*0d6140beSAndroid Build Coastguard Worker ctrl | ASM106X_CTRL_RUN | chunk);
95*0d6140beSAndroid Build Coastguard Worker if (asm106x_wait_ready(data->pci, NULL))
96*0d6140beSAndroid Build Coastguard Worker goto out;
97*0d6140beSAndroid Build Coastguard Worker
98*0d6140beSAndroid Build Coastguard Worker uint32_t val = pci_read_long(data->pci, ASM106X_REG_DATA);
99*0d6140beSAndroid Build Coastguard Worker msg_pdbg2("asm106x read %#08"PRIx32" chunk %u\n", val, chunk);
100*0d6140beSAndroid Build Coastguard Worker for (unsigned int k = 0; k < chunk; k++) {
101*0d6140beSAndroid Build Coastguard Worker readarr[k] = val & 0xff;
102*0d6140beSAndroid Build Coastguard Worker val >>= 8;
103*0d6140beSAndroid Build Coastguard Worker }
104*0d6140beSAndroid Build Coastguard Worker readcnt -= chunk;
105*0d6140beSAndroid Build Coastguard Worker readarr += chunk;
106*0d6140beSAndroid Build Coastguard Worker }
107*0d6140beSAndroid Build Coastguard Worker
108*0d6140beSAndroid Build Coastguard Worker rv = 0;
109*0d6140beSAndroid Build Coastguard Worker out:
110*0d6140beSAndroid Build Coastguard Worker pci_write_byte(data->pci, ASM106X_REG_CTRL, ctrl | ASM106X_CTRL_CSN);
111*0d6140beSAndroid Build Coastguard Worker return rv;
112*0d6140beSAndroid Build Coastguard Worker }
113*0d6140beSAndroid Build Coastguard Worker
asm106x_shutdown(void * data)114*0d6140beSAndroid Build Coastguard Worker static int asm106x_shutdown(void *data)
115*0d6140beSAndroid Build Coastguard Worker {
116*0d6140beSAndroid Build Coastguard Worker free(data);
117*0d6140beSAndroid Build Coastguard Worker return 0;
118*0d6140beSAndroid Build Coastguard Worker }
119*0d6140beSAndroid Build Coastguard Worker
120*0d6140beSAndroid Build Coastguard Worker static const struct spi_master asm106x_spi_master = {
121*0d6140beSAndroid Build Coastguard Worker .features = SPI_MASTER_4BA,
122*0d6140beSAndroid Build Coastguard Worker .max_data_read = MAX_DATA_READ_UNLIMITED,
123*0d6140beSAndroid Build Coastguard Worker .max_data_write = MAX_DATA_WRITE_UNLIMITED,
124*0d6140beSAndroid Build Coastguard Worker .command = asm106x_command,
125*0d6140beSAndroid Build Coastguard Worker .shutdown = asm106x_shutdown,
126*0d6140beSAndroid Build Coastguard Worker .read = default_spi_read,
127*0d6140beSAndroid Build Coastguard Worker .write_256 = default_spi_write_256,
128*0d6140beSAndroid Build Coastguard Worker };
129*0d6140beSAndroid Build Coastguard Worker
asm106x_init(const struct programmer_cfg * cfg)130*0d6140beSAndroid Build Coastguard Worker static int asm106x_init(const struct programmer_cfg *cfg)
131*0d6140beSAndroid Build Coastguard Worker {
132*0d6140beSAndroid Build Coastguard Worker struct pci_dev *pci;
133*0d6140beSAndroid Build Coastguard Worker struct asm106x_data *data;
134*0d6140beSAndroid Build Coastguard Worker
135*0d6140beSAndroid Build Coastguard Worker /* TODO: no BAR required (just config space) */
136*0d6140beSAndroid Build Coastguard Worker pci = pcidev_init(cfg, asm106x_devs, PCI_ROM_ADDRESS);
137*0d6140beSAndroid Build Coastguard Worker if (!pci)
138*0d6140beSAndroid Build Coastguard Worker return 1;
139*0d6140beSAndroid Build Coastguard Worker
140*0d6140beSAndroid Build Coastguard Worker data = calloc(1, sizeof(*data));
141*0d6140beSAndroid Build Coastguard Worker if (!data) {
142*0d6140beSAndroid Build Coastguard Worker msg_perr("cannot allocate memory for asm106x_data\n");
143*0d6140beSAndroid Build Coastguard Worker return 1;
144*0d6140beSAndroid Build Coastguard Worker }
145*0d6140beSAndroid Build Coastguard Worker data->pci = pci;
146*0d6140beSAndroid Build Coastguard Worker return register_spi_master(&asm106x_spi_master, data);
147*0d6140beSAndroid Build Coastguard Worker }
148*0d6140beSAndroid Build Coastguard Worker
149*0d6140beSAndroid Build Coastguard Worker const struct programmer_entry programmer_asm106x = {
150*0d6140beSAndroid Build Coastguard Worker .name = "asm106x",
151*0d6140beSAndroid Build Coastguard Worker .type = PCI,
152*0d6140beSAndroid Build Coastguard Worker .devs.dev = asm106x_devs,
153*0d6140beSAndroid Build Coastguard Worker .init = asm106x_init,
154*0d6140beSAndroid Build Coastguard Worker };
155