1233542Sjchandra/*- 2233542Sjchandra * Copyright (c) 2003-2012 Broadcom Corporation 3233542Sjchandra * All Rights Reserved 4233542Sjchandra * 5233542Sjchandra * Redistribution and use in source and binary forms, with or without 6233542Sjchandra * modification, are permitted provided that the following conditions 7233542Sjchandra * are met: 8233542Sjchandra * 9233542Sjchandra * 1. Redistributions of source code must retain the above copyright 10233542Sjchandra * notice, this list of conditions and the following disclaimer. 11233542Sjchandra * 2. Redistributions in binary form must reproduce the above copyright 12233542Sjchandra * notice, this list of conditions and the following disclaimer in 13233542Sjchandra * the documentation and/or other materials provided with the 14233542Sjchandra * distribution. 15279387Sjchandra * 16233542Sjchandra * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR 17233542Sjchandra * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18233542Sjchandra * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19233542Sjchandra * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE 20233542Sjchandra * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21233542Sjchandra * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22233542Sjchandra * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23233542Sjchandra * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24233542Sjchandra * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25233542Sjchandra * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 26233542Sjchandra * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27233542Sjchandra */ 28233542Sjchandra 29233542Sjchandra#include <sys/cdefs.h> 30233542Sjchandra__FBSDID("$FreeBSD: releng/11.0/sys/mips/nlm/board_eeprom.c 279387 2015-02-28 00:17:29Z jchandra $"); 31233542Sjchandra#include <sys/param.h> 32233542Sjchandra#include <sys/endian.h> 33233542Sjchandra#include <sys/systm.h> 34233542Sjchandra#include <sys/kernel.h> 35233542Sjchandra#include <sys/limits.h> 36233542Sjchandra#include <sys/bus.h> 37233542Sjchandra 38233542Sjchandra#include <dev/iicbus/iicoc.h> 39233542Sjchandra 40233542Sjchandra#include <mips/nlm/hal/haldefs.h> 41233542Sjchandra#include <mips/nlm/hal/iomap.h> 42233542Sjchandra#include <mips/nlm/hal/mips-extns.h> /* needed by board.h */ 43233542Sjchandra 44233542Sjchandra#include <mips/nlm/board.h> 45233542Sjchandra 46233542Sjchandra/* 47233542Sjchandra * We have to read the EEPROM in early boot (now only for MAC addr) 48233542Sjchandra * but later for board information. Use simple polled mode driver 49233542Sjchandra * for I2C 50233542Sjchandra */ 51233542Sjchandra#define oc_read_reg(reg) nlm_read_reg(eeprom_i2c_base, reg) 52233542Sjchandra#define oc_write_reg(reg, val) nlm_write_reg(eeprom_i2c_base, reg, val) 53233542Sjchandra 54233542Sjchandrastatic uint64_t eeprom_i2c_base; 55233542Sjchandra 56233542Sjchandrastatic int 57233542Sjchandraoc_wait_on_status(uint8_t bit) 58233542Sjchandra{ 59233542Sjchandra int tries = I2C_TIMEOUT; 60233542Sjchandra uint8_t status; 61233542Sjchandra 62233542Sjchandra do { 63233542Sjchandra status = oc_read_reg(OC_I2C_STATUS_REG); 64233542Sjchandra } while ((status & bit) != 0 && --tries > 0); 65233542Sjchandra 66233542Sjchandra return (tries == 0 ? -1: 0); 67233542Sjchandra} 68233542Sjchandra 69233542Sjchandrastatic int 70233542Sjchandraoc_rd_cmd(uint8_t cmd) 71233542Sjchandra{ 72233542Sjchandra uint8_t data; 73233542Sjchandra 74233542Sjchandra oc_write_reg(OC_I2C_CMD_REG, cmd); 75233542Sjchandra if (oc_wait_on_status(OC_STATUS_TIP) < 0) 76233542Sjchandra return (-1); 77233542Sjchandra 78233542Sjchandra data = oc_read_reg(OC_I2C_DATA_REG); 79233542Sjchandra return (data); 80233542Sjchandra} 81279387Sjchandra 82233542Sjchandrastatic int 83233542Sjchandraoc_wr_cmd(uint8_t data, uint8_t cmd) 84233542Sjchandra{ 85233542Sjchandra oc_write_reg(OC_I2C_DATA_REG, data); 86233542Sjchandra oc_write_reg(OC_I2C_CMD_REG, cmd); 87233542Sjchandra 88233542Sjchandra if (oc_wait_on_status(OC_STATUS_TIP) < 0) 89233542Sjchandra return (-1); 90233542Sjchandra return (0); 91233542Sjchandra} 92233542Sjchandra 93233542Sjchandraint 94233542Sjchandranlm_board_eeprom_read(int node, int bus, int addr, int offs, uint8_t *buf, 95233542Sjchandra int sz) 96233542Sjchandra{ 97233542Sjchandra int rd, i; 98233542Sjchandra char *err = NULL; 99233542Sjchandra 100233542Sjchandra eeprom_i2c_base = nlm_pcicfg_base(XLP_IO_I2C_OFFSET(node, bus)) + 101233542Sjchandra XLP_IO_PCI_HDRSZ; 102233542Sjchandra 103233542Sjchandra if (oc_wait_on_status(OC_STATUS_BUSY) < 0) { 104233542Sjchandra err = "Not idle"; 105233542Sjchandra goto err_exit; 106233542Sjchandra } 107233542Sjchandra 108233542Sjchandra /* write start */ 109233542Sjchandra if (oc_wr_cmd(addr, OC_COMMAND_START)) { 110233542Sjchandra err = "I2C write start failed."; 111233542Sjchandra goto err_exit; 112233542Sjchandra } 113233542Sjchandra 114233542Sjchandra if (oc_read_reg(OC_I2C_STATUS_REG) & OC_STATUS_NACK) { 115233542Sjchandra err = "No ack after start"; 116233542Sjchandra goto err_exit_stop; 117233542Sjchandra } 118233542Sjchandra 119233542Sjchandra if (oc_read_reg(OC_I2C_STATUS_REG) & OC_STATUS_AL) { 120233542Sjchandra err = "I2C Bus Arbitration Lost"; 121233542Sjchandra goto err_exit_stop; 122233542Sjchandra } 123233542Sjchandra 124233542Sjchandra /* Write offset */ 125233542Sjchandra if (oc_wr_cmd(offs, OC_COMMAND_WRITE)) { 126233542Sjchandra err = "I2C write slave offset failed."; 127233542Sjchandra goto err_exit_stop; 128233542Sjchandra } 129233542Sjchandra 130233542Sjchandra if (oc_read_reg(OC_I2C_STATUS_REG) & OC_STATUS_NACK) { 131233542Sjchandra err = "No ack after write"; 132233542Sjchandra goto err_exit_stop; 133233542Sjchandra } 134233542Sjchandra 135233542Sjchandra /* read start */ 136233542Sjchandra if (oc_wr_cmd(addr | 1, OC_COMMAND_START)) { 137233542Sjchandra err = "I2C read start failed."; 138233542Sjchandra goto err_exit_stop; 139233542Sjchandra } 140233542Sjchandra 141233542Sjchandra if (oc_read_reg(OC_I2C_STATUS_REG) & OC_STATUS_NACK) { 142233542Sjchandra err = "No ack after read start"; 143233542Sjchandra goto err_exit_stop; 144233542Sjchandra } 145279387Sjchandra 146233542Sjchandra for (i = 0; i < sz - 1; i++) { 147233542Sjchandra if ((rd = oc_rd_cmd(OC_COMMAND_READ)) < 0) { 148233542Sjchandra err = "I2C read data byte failed."; 149233542Sjchandra goto err_exit_stop; 150233542Sjchandra } 151233542Sjchandra buf[i] = rd; 152233542Sjchandra } 153233542Sjchandra 154233542Sjchandra /* last byte */ 155233542Sjchandra if ((rd = oc_rd_cmd(OC_COMMAND_RDNACK)) < 0) { 156233542Sjchandra err = "I2C read last data byte failed."; 157233542Sjchandra goto err_exit_stop; 158233542Sjchandra } 159233542Sjchandra buf[sz - 1] = rd; 160233542Sjchandra 161233542Sjchandraerr_exit_stop: 162233542Sjchandra oc_write_reg(OC_I2C_CMD_REG, OC_COMMAND_STOP); 163233542Sjchandra if (oc_wait_on_status(OC_STATUS_BUSY) < 0) 164233542Sjchandra printf("%s: stop failed", __func__); 165233542Sjchandra 166233542Sjchandraerr_exit: 167233542Sjchandra if (err) { 168233542Sjchandra printf("%s: Failed (%s)\n", __func__, err); 169233542Sjchandra return (-1); 170233542Sjchandra } 171233542Sjchandra return (0); 172233542Sjchandra} 173