1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2003-2012 Broadcom Corporation 5 * All Rights Reserved 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 25 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 27 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 28 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD$"); 33#include <sys/param.h> 34#include <sys/endian.h> 35#include <sys/systm.h> 36#include <sys/kernel.h> 37#include <sys/limits.h> 38#include <sys/bus.h> 39 40#include <dev/iicbus/iicoc.h> 41 42#include <mips/nlm/hal/haldefs.h> 43#include <mips/nlm/hal/iomap.h> 44#include <mips/nlm/hal/mips-extns.h> /* needed by board.h */ 45 46#include <mips/nlm/board.h> 47 48/* 49 * We have to read the EEPROM in early boot (now only for MAC addr) 50 * but later for board information. Use simple polled mode driver 51 * for I2C 52 */ 53#define oc_read_reg(reg) nlm_read_reg(eeprom_i2c_base, reg) 54#define oc_write_reg(reg, val) nlm_write_reg(eeprom_i2c_base, reg, val) 55 56static uint64_t eeprom_i2c_base; 57 58static int 59oc_wait_on_status(uint8_t bit) 60{ 61 int tries = I2C_TIMEOUT; 62 uint8_t status; 63 64 do { 65 status = oc_read_reg(OC_I2C_STATUS_REG); 66 } while ((status & bit) != 0 && --tries > 0); 67 68 return (tries == 0 ? -1: 0); 69} 70 71static int 72oc_rd_cmd(uint8_t cmd) 73{ 74 uint8_t data; 75 76 oc_write_reg(OC_I2C_CMD_REG, cmd); 77 if (oc_wait_on_status(OC_STATUS_TIP) < 0) 78 return (-1); 79 80 data = oc_read_reg(OC_I2C_DATA_REG); 81 return (data); 82} 83 84static int 85oc_wr_cmd(uint8_t data, uint8_t cmd) 86{ 87 oc_write_reg(OC_I2C_DATA_REG, data); 88 oc_write_reg(OC_I2C_CMD_REG, cmd); 89 90 if (oc_wait_on_status(OC_STATUS_TIP) < 0) 91 return (-1); 92 return (0); 93} 94 95int 96nlm_board_eeprom_read(int node, int bus, int addr, int offs, uint8_t *buf, 97 int sz) 98{ 99 int rd, i; 100 char *err = NULL; 101 102 eeprom_i2c_base = nlm_pcicfg_base(XLP_IO_I2C_OFFSET(node, bus)) + 103 XLP_IO_PCI_HDRSZ; 104 105 if (oc_wait_on_status(OC_STATUS_BUSY) < 0) { 106 err = "Not idle"; 107 goto err_exit; 108 } 109 110 /* write start */ 111 if (oc_wr_cmd(addr, OC_COMMAND_START)) { 112 err = "I2C write start failed."; 113 goto err_exit; 114 } 115 116 if (oc_read_reg(OC_I2C_STATUS_REG) & OC_STATUS_NACK) { 117 err = "No ack after start"; 118 goto err_exit_stop; 119 } 120 121 if (oc_read_reg(OC_I2C_STATUS_REG) & OC_STATUS_AL) { 122 err = "I2C Bus Arbitration Lost"; 123 goto err_exit_stop; 124 } 125 126 /* Write offset */ 127 if (oc_wr_cmd(offs, OC_COMMAND_WRITE)) { 128 err = "I2C write slave offset failed."; 129 goto err_exit_stop; 130 } 131 132 if (oc_read_reg(OC_I2C_STATUS_REG) & OC_STATUS_NACK) { 133 err = "No ack after write"; 134 goto err_exit_stop; 135 } 136 137 /* read start */ 138 if (oc_wr_cmd(addr | 1, OC_COMMAND_START)) { 139 err = "I2C read start failed."; 140 goto err_exit_stop; 141 } 142 143 if (oc_read_reg(OC_I2C_STATUS_REG) & OC_STATUS_NACK) { 144 err = "No ack after read start"; 145 goto err_exit_stop; 146 } 147 148 for (i = 0; i < sz - 1; i++) { 149 if ((rd = oc_rd_cmd(OC_COMMAND_READ)) < 0) { 150 err = "I2C read data byte failed."; 151 goto err_exit_stop; 152 } 153 buf[i] = rd; 154 } 155 156 /* last byte */ 157 if ((rd = oc_rd_cmd(OC_COMMAND_RDNACK)) < 0) { 158 err = "I2C read last data byte failed."; 159 goto err_exit_stop; 160 } 161 buf[sz - 1] = rd; 162 163err_exit_stop: 164 oc_write_reg(OC_I2C_CMD_REG, OC_COMMAND_STOP); 165 if (oc_wait_on_status(OC_STATUS_BUSY) < 0) 166 printf("%s: stop failed", __func__); 167 168err_exit: 169 if (err) { 170 printf("%s: Failed (%s)\n", __func__, err); 171 return (-1); 172 } 173 return (0); 174} 175