meta-facebook/meta-fby2/recipes-fby2/asd/files/interface/pin_interface.c (534 lines of code) (raw):

/* Copyright (c) 2017, Intel Corporation Copyright (c) 2017, Facebook Inc. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "pin_interface.h" #include "SoftwareJTAGHandler.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <syslog.h> #include <sys/socket.h> #include <sys/un.h> #include "openbmc/pal.h" #include "openbmc/gpio.h" #include <facebook/bic.h> #include <facebook/fby2_sensor.h> //#define FBY2_DEBUG // PLTRST, PRDY, XDP_PRESENT enum MONITOR_EVENTS { JTAG_PLTRST_EVENT = 0, JTAG_PRDY_EVENT, JTAG_XDP_PRESENT_EVENT, JTAG_EVENT_NUM, }; static bool g_gpios_triggered[JTAG_EVENT_NUM] = {false, false, false}; static pthread_mutex_t triggered_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_t poll_thread; static void *gpio_poll_thread(void *arg); static int g_dev_id = 0; static int get_asd_dev_config(uint8_t fru) { FILE *fp = NULL; int dev_id = 0; char file_path[128] = {0}; snprintf(file_path, sizeof(file_path), "%s_slot%d", ASD_DEV_CONFIG_FILE, fru); fp = fopen(file_path, "r"); if (fp == NULL) { return -1; } if (fscanf(fp, "%d", &dev_id) != 1) { syslog(LOG_WARNING, "%s: read file failed, file: %s", __func__, file_path); dev_id = -1; } fclose(fp); return dev_id; } static int sph_pin_conf(uint8_t slot_id) { int ret = 0, retry = 5, bus = 0; uint8_t tbuf[256] = {0x18, 0x52, 0x05, 0xD4, 0x05, 0x8E, 0x8, 0x08, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xB, 0xB, 0x8, 0x8, 0x8, 0x8, 0x8, 0xB}; uint8_t rbuf[256] = {0x00}; uint8_t tlen = 21; uint8_t rlen = 0; bus = pal_dev_jtag_gpio_to_bus(slot_id); tbuf[2] = bus; // Read existing FPGA Output pins status. while (retry >= 0) { ret = bic_ipmb_wrapper_with_dev_mux_selection(slot_id, g_dev_id, tbuf[0] >> 2, tbuf[1], &tbuf[2], tlen-2, rbuf, &rlen); if (ret == 0) break; retry--; } if (ret) { syslog(LOG_ERR, "%s: BIC no response!\n", __FUNCTION__); return ret; } return 0; } int pin_initialize(const int fru) { static bool gpios_polling = false; int ret = 0; g_dev_id = get_asd_dev_config(fru); if (g_dev_id < 0) { syslog(LOG_ERR, "%s: Fail to get the ASD configuration for fru %d\n", __FUNCTION__, fru); } #ifdef FBY2_DEBUG syslog(LOG_DEBUG, "%s, fru=%d", __FUNCTION__, fru); #endif if (fby2_get_slot_type(fru) == SLOT_TYPE_GPV2) { ret = sph_pin_conf(fru); if (ret != 0) { syslog(LOG_ERR, "%s: pin_conf failed, fru=%d", __FUNCTION__, fru); return ST_ERR; } } else { // For Twinlake ASD if ((fru < FRU_SLOT1) || (fru > FRU_SLOT4)) { syslog(LOG_ERR, "%s: invalid fru: %d", __FUNCTION__, fru); return ST_ERR; } /* Platform specific enables which are required for the ASD feature */ /* needs to * - enable DEBUG_EN * - enable POWER_DEBUG_EN (XDP_BIC_PWR_DEBUG_N?) * - FM_JTAG_BIC_TCK_MUX_SEL_N (select ?) * * starts 1 thread monitoring GPIO pins * PLTRST_BUF_N - both edge * PRDY - fallign edge * XDP_PRSNT_IN_N - both edges (if triggered, disable asd) */ // enable DEBUG_EN = XDP_PRSNT_OUT_N pin // active low if (bic_set_gpio(fru, XDP_PRSNT_OUT_N, GPIO_VALUE_LOW)) { syslog(LOG_ERR, "%s: assert XDP_PRSNT_OUT_N failed, fru=%d", __FUNCTION__, fru); return ST_ERR; } // enable FM_JTAG_BIC_TCK_MUX_SEL_N = FM_BIC_JTAG_SEL_N pin // active low if (bic_set_gpio(fru, FM_JTAG_BIC_TCK_MUX_SEL_N, GPIO_VALUE_LOW)) { syslog(LOG_ERR, "%s: assert FM_JTAG_BIC_TCK_MUX_SEL_N failed, fru=%d", __FUNCTION__, fru); return ST_ERR; }; // set FM_BIC_JTAG_SEL_N = 1 to enable ASD if (bic_set_gpio(fru, FM_BIC_JTAG_SEL_N, GPIO_VALUE_HIGH)) { syslog(LOG_ERR, "%s: assert FM_BIC_JTAG_SEL_N failed, fru=%d", __FUNCTION__, fru); return ST_ERR; }; /* Start the GPIO polling threads just once */ if (gpios_polling == false) { pthread_create(&poll_thread, NULL, gpio_poll_thread, (void *)fru); gpios_polling = true; } else { pthread_mutex_lock(&triggered_mutex); g_gpios_triggered[JTAG_PLTRST_EVENT] = false; g_gpios_triggered[JTAG_PRDY_EVENT] = false; g_gpios_triggered[JTAG_XDP_PRESENT_EVENT] = false; pthread_mutex_unlock(&triggered_mutex); } } return ST_OK; } int pin_deinitialize(const int fru) { #ifdef FBY2_DEBUG syslog(LOG_DEBUG, "%s, fru=%d", __FUNCTION__, fru); #endif if (fby2_get_slot_type(fru) != SLOT_TYPE_GPV2) { if ((fru < FRU_SLOT1) || (fru > FRU_SLOT4)) { syslog(LOG_ERR, "%s: invalid fru: %d", __FUNCTION__, fru); return ST_ERR; } // disable DEBUG_EN = XDP_PRSNT_OUT_N pin // active low if (bic_set_gpio(fru, XDP_PRSNT_OUT_N, GPIO_VALUE_HIGH)) { syslog(LOG_ERR, "%s: de-assert XDP_PRSNT_OUT_N failed, fru=%d", __FUNCTION__, fru); return ST_ERR; } // disable FM_JTAG_BIC_TCK_MUX_SEL_N = FM_BIC_JTAG_SEL_N pin // active low if (bic_set_gpio(fru, FM_JTAG_BIC_TCK_MUX_SEL_N, GPIO_VALUE_HIGH)) { syslog(LOG_ERR, "%s: de-assert FM_JTAG_BIC_TCK_MUX_SEL_N failed, fru=%d", __FUNCTION__, fru); return ST_ERR; }; // set FM_BIC_JTAG_SEL_N = 0 to disable ASD if (bic_set_gpio(fru, FM_BIC_JTAG_SEL_N, GPIO_VALUE_LOW)) { syslog(LOG_ERR, "%s: assert FM_BIC_JTAG_SEL_N failed, fru=%d", __FUNCTION__, fru); return ST_ERR; }; } return ST_OK; } // power_debug_assert pin = "XDP_BIC_PWR_DEBUG_N", xdp_bic_pwr_debug_n int power_debug_assert(const int fru, const bool assert) { int ret; #ifdef FBY2_DEBUG syslog(LOG_DEBUG, "%s, fru=%d, assert=%d", __FUNCTION__, fru, assert); #endif if ((fru < FRU_SLOT1) || (fru > FRU_SLOT4)) { syslog(LOG_ERR, "%s: invalid fru: %d", __FUNCTION__, fru); return ST_ERR; } /* active low */ ret = bic_set_gpio(fru, XDP_BIC_PWR_DEBUG_N, assert ? GPIO_VALUE_LOW : GPIO_VALUE_HIGH); return ret; } // power_debug_assert pin = "XDP_BIC_PWR_DEBUG_N", xdp_bic_pwr_debug_n int power_debug_is_asserted(const int fru, bool* asserted) { uint8_t gpio; int ret; if (fby2_get_slot_type(fru) != SLOT_TYPE_GPV2) { if ((fru < FRU_SLOT1) || (fru > FRU_SLOT4)) { syslog(LOG_ERR, "%s: invalid fru: %d", __FUNCTION__, fru); return ST_ERR; } ret = bic_get_gpio_status(fru, XDP_BIC_PWR_DEBUG_N, &gpio); if (!ret) { /* active low */ *asserted = gpio == GPIO_VALUE_LOW ? true : false; } #ifdef FBY2_DEBUG if (*asserted) syslog(LOG_DEBUG, "%s, fru=%d asserted", __FUNCTION__, fru); #endif return ret; } else { return 0; } } static int sph_preq(uint8_t slot_id, uint8_t *gpio) { int ret = 0, retry = 5, bus = 0; uint8_t tbuf[256] = {0x18, 0x52, 0x05, 0xD4, 0x05, 0x8E}; uint8_t rbuf[256] = {0x00}; uint8_t tlen = 6; uint8_t rlen = 0; bus = pal_dev_jtag_gpio_to_bus(slot_id); tbuf[2] = bus; // Read existing FPGA Output pins status. while (retry >= 0) { ret = bic_ipmb_wrapper_with_dev_mux_selection(slot_id, g_dev_id, tbuf[0]>>2, tbuf[1], &tbuf[2], tlen-2, rbuf, &rlen); if (ret == 0) break; retry--; } *gpio = (1 & (rbuf[2] >> 6)); return 0; } static int sph_preq_set(uint8_t slot_id, uint8_t select) { int i = 0, ret = 0, retry = 5, bus = 0; uint8_t tbuf[256] = {0x18, 0x52, 0x05, 0xD4, 0x05, 0x8D}; uint8_t rbuf[256] = {0x00}; uint8_t tlen = 6; uint8_t rlen = 0; bus = pal_dev_jtag_gpio_to_bus(slot_id); tbuf[2] = bus; // Read existing FPGA Output pins status. while (retry >= 0) { ret = bic_ipmb_wrapper_with_dev_mux_selection(slot_id, g_dev_id, tbuf[0]>>2, tbuf[1], &tbuf[2], tlen-2, rbuf, &rlen); if (ret == 0) break; retry--; } for (i = 0; i < rlen; i++) { tbuf[6 + i] = rbuf[i]; } tlen += (rlen - 1); { tbuf[8] = tbuf[8] & 0x7F; if( select == 0 ) tbuf[8] |= 0 << 7; else tbuf[8] |= 1 << 7; retry = 5; while (retry >= 0) { ret = bic_ipmb_wrapper_with_dev_mux_selection(slot_id, g_dev_id, tbuf[0]>>2, tbuf[1], &tbuf[2], tlen-2, rbuf, &rlen); if (ret == 0) break; retry--; } if (ret) { syslog(LOG_ERR, "%s: BIC no response!\n", __FUNCTION__); return ret; } } return 0; } // preq pin = ""XDP_BIC_PREQ_N"", xdp_bic_preq_n int preq_assert(const int fru, const bool assert) { int ret; #ifdef FBY2_DEBUG syslog(LOG_DEBUG, "%s, fru=%d, assert=%d", __FUNCTION__, fru, assert); #endif if (fby2_get_slot_type(fru) != SLOT_TYPE_GPV2) { if ((fru < FRU_SLOT1) || (fru > FRU_SLOT4)) { syslog(LOG_ERR, "%s: invalid fru: %d", __FUNCTION__, fru); return ST_ERR; } /* active low */ ret = bic_set_gpio(fru, XDP_BIC_PREQ_N, assert ? GPIO_VALUE_LOW : GPIO_VALUE_HIGH); } else { ret = sph_preq_set(fru, assert ? GPIO_VALUE_LOW : GPIO_VALUE_HIGH); } return ret; } // preq pin = ""XDP_BIC_PREQ_N"", xdp_bic_preq_n int preq_is_asserted(const int fru, bool* asserted) { uint8_t gpio; int ret; if (fby2_get_slot_type(fru) != SLOT_TYPE_GPV2) { if ((fru < FRU_SLOT1) || (fru > FRU_SLOT4)) { syslog(LOG_ERR, "%s: invalid fru: %d", __FUNCTION__, fru); return ST_ERR; } ret = bic_get_gpio_status(fru, XDP_BIC_PREQ_N, &gpio); if (!ret) { /* active low */ *asserted = gpio == GPIO_VALUE_LOW ? true : false; } } else { ret = sph_preq(fru, &gpio); if (!ret) { /* active low */ *asserted = gpio == GPIO_VALUE_LOW ? true : false; } } #ifdef FBY2_DEBUG if (*asserted) syslog(LOG_DEBUG, "%s, fru=%d asserted", __FUNCTION__, fru); #endif return ret; } static int sph_prdy_get(uint8_t slot_id, uint8_t* gpio) { int ret = 0, retry = 5, bus = 0; uint8_t tbuf[256] = {0x18, 0x52, 0x05, 0xD4, 0x05, 0x8E}; uint8_t rbuf[256] = {0x00}; uint8_t tlen = 6; uint8_t rlen = 0; bus = pal_dev_jtag_gpio_to_bus(slot_id); tbuf[2] = bus; // Read existing FPGA Output pins status. while (retry >= 0) { ret = bic_ipmb_wrapper_with_dev_mux_selection(slot_id, g_dev_id, tbuf[0]>>2, tbuf[1], &tbuf[2], tlen-2, rbuf, &rlen); if (ret == 0) break; retry--; } *gpio = ( 1 & (rbuf[2] >> 6) ); return 0; } // open a socket and waits for communcation from ipmid static void *gpio_poll_thread(void *fru) { int sock, msgsock, n, len, gpio_pin, ret=0; size_t t; struct sockaddr_un server, client; unsigned char req_buf[256]; char sock_path[64] = {0}; if ((sock = socket (AF_UNIX, SOCK_STREAM, 0)) == -1) { syslog(LOG_ERR, "ASD_BIC: socket() failed\n"); exit (1); } server.sun_family = AF_UNIX; sprintf(sock_path, "%s_%d", SOCK_PATH_ASD_BIC, (int)fru); strcpy(server.sun_path, sock_path); unlink (server.sun_path); len = strlen (server.sun_path) + sizeof (server.sun_family); if (bind (sock, (struct sockaddr *) &server, len) == -1) { syslog(LOG_ERR, "ASD_BIC: bind() failed, errno=%d", errno); exit (1); } syslog(LOG_DEBUG, "ASD_BIC: Socket has name %s", server.sun_path); if (listen (sock, 5) == -1) { syslog(LOG_ERR, "ASD_BIC: listen() failed, errno=%d", errno); exit (1); } while (1) { t = sizeof (client); if ((msgsock = accept(sock, (struct sockaddr *) &client, &t)) < 0) { ret = errno; syslog(LOG_WARNING, "ASD_BIC: accept() failed with ret: %x, errno: %x\n", msgsock, ret); sleep(1); continue; } n = recv(msgsock, req_buf, sizeof(req_buf), 0); if (n <= 0) { syslog(LOG_WARNING, "ASD_BIC: recv() failed with %d\n", n); sleep(1); continue; } else { #ifdef FBY2_DEBUG syslog(LOG_DEBUG, "message received, %d %d", req_buf[0], req_buf[1]); #endif gpio_pin = req_buf[0]; pthread_mutex_lock(&triggered_mutex); switch (gpio_pin) { case PLTRST_N: #ifdef FBY2_DEBUG syslog(LOG_DEBUG, "ASD_BIC: PLTRST_N event"); #endif g_gpios_triggered[JTAG_PLTRST_EVENT] = true;; break; case XDP_BIC_PRDY_N: #ifdef FBY2_DEBUG syslog(LOG_DEBUG, "ASD_BIC: PRDY event, trigger type=%d", req_buf[1]); #endif // only record falling edge if (req_buf[1] == 0) g_gpios_triggered[JTAG_PRDY_EVENT] = true;; break; case XDP_PRSNT_IN_N: #ifdef FBY2_DEBUG syslog(LOG_DEBUG, "ASD_BIC: XDP_PRESENT event, trigger type=%d", req_buf[1]); #endif // triggers on falling edge if (req_buf[1] == 0) g_gpios_triggered[JTAG_XDP_PRESENT_EVENT] = true;; break; default: syslog(LOG_ERR, "ASD BIC: unknown GPIO pin # received, %d", gpio_pin); } pthread_mutex_unlock(&triggered_mutex); } close(msgsock); } close(sock); return NULL; } int platform_reset_is_event_triggered(const int fru, bool* triggered) { if ((fru < FRU_SLOT1) || (fru > FRU_SLOT4)) { syslog(LOG_ERR, "%s: invalid fru: %d", __FUNCTION__, fru); return ST_ERR; } pthread_mutex_lock(&triggered_mutex); *triggered = g_gpios_triggered[JTAG_PLTRST_EVENT]; g_gpios_triggered[JTAG_PLTRST_EVENT] = false; pthread_mutex_unlock(&triggered_mutex); #ifdef FBY2_DEBUG if (*triggered) syslog(LOG_DEBUG, "%s fru=%d, triggered", __FUNCTION__, fru); #endif return ST_OK; } // platform_reset pin = pltrst_n int platform_reset_is_asserted(const int fru, bool* asserted) { uint8_t gpio; int ret; if (fby2_get_slot_type(fru) != SLOT_TYPE_GPV2) { if ((fru < FRU_SLOT1) || (fru > FRU_SLOT4)) { syslog(LOG_ERR, "%s: invalid fru: %d", __FUNCTION__, fru); return ST_ERR; } ret = bic_get_gpio_status(fru, PLTRST_N, &gpio); if (!ret) { /* active low */ *asserted = gpio == GPIO_VALUE_LOW ? true : false; } } else { ret = sph_prdy_get(fru, &gpio); if (!ret) { /* active low */ *asserted = gpio == GPIO_VALUE_LOW ? true : false; } } #ifdef FBY2_DEBUG if (*asserted) syslog(LOG_DEBUG, "%s fru=%d asserted", __FUNCTION__, fru); #endif return ST_OK; } int prdy_is_event_triggered(const int fru, bool* triggered) { if ((fru < FRU_SLOT1) || (fru > FRU_SLOT4)) { syslog(LOG_ERR, "%s: invalid fru: %d", __FUNCTION__, fru); return ST_ERR; } pthread_mutex_lock(&triggered_mutex); *triggered = g_gpios_triggered[JTAG_PRDY_EVENT]; g_gpios_triggered[JTAG_PRDY_EVENT] = false; pthread_mutex_unlock(&triggered_mutex); #ifdef FBY2_DEBUG if (*triggered) syslog(LOG_DEBUG, "%s fru=%d triggered", __FUNCTION__, fru); #endif return ST_OK; } // pready pin = xdp_bic_prdy_n int prdy_is_asserted(const int fru, bool* asserted) { uint8_t gpio; int ret; if ((fru < FRU_SLOT1) || (fru > FRU_SLOT4)) { syslog(LOG_ERR, "%s: invalid fru: %d", __FUNCTION__, fru); return ST_ERR; } ret = bic_get_gpio_status(fru, XDP_BIC_PRDY_N, &gpio); if (!ret) { /* active low */ *asserted = gpio == GPIO_VALUE_LOW ? true : false; } else { syslog(LOG_ERR, "%s: error getting GPIO. fru: %d", __FUNCTION__, fru); } #ifdef FBY2_DEBUG if (*asserted) syslog(LOG_DEBUG, "%s fru=%d asserted", __FUNCTION__, fru); #endif return ret; } int xdp_present_is_event_triggered(const int fru, bool* triggered) { if ((fru < FRU_SLOT1) || (fru > FRU_SLOT4)) { syslog(LOG_ERR, "%s: invalid fru: %d", __FUNCTION__, fru); return ST_ERR; } pthread_mutex_lock(&triggered_mutex); *triggered = g_gpios_triggered[JTAG_XDP_PRESENT_EVENT]; g_gpios_triggered[JTAG_XDP_PRESENT_EVENT] = false; pthread_mutex_unlock(&triggered_mutex); #ifdef FBY2_DEBUG if (*triggered) syslog(LOG_DEBUG, "%s fru=%d triggered", __FUNCTION__, fru); #endif return ST_OK; } // xdp present pin = XDP_PRSNT_IN_N, xdp_prsnt_in_n int xdp_present_is_asserted(const int fru, bool* asserted) { uint8_t gpio; int ret; if ((fru < FRU_SLOT1) || (fru > FRU_SLOT4)) { syslog(LOG_ERR, "%s: invalid fru: %d", __FUNCTION__, fru); return ST_ERR; } ret = bic_get_gpio_status(fru, XDP_PRSNT_IN_N, &gpio); if (!ret) { /* active low */ *asserted = gpio == GPIO_VALUE_LOW ? true : false; } else { syslog(LOG_ERR, "%s: error getting GPIO. fru: %d", __FUNCTION__, fru); } #ifdef FBY2_DEBUG if (*asserted) syslog(LOG_DEBUG, "%s fru=%d asserted", __FUNCTION__, fru); #endif return ret; } static int set_sph_mux_command(uint8_t slot_id, uint8_t select) { int i = 0, ret = 0, retry = 5, bus = 0; uint8_t tbuf[256] = {0x18, 0x52, 0x05, 0xD4, 0x05, 0x8D}; uint8_t rbuf[256] = {0x00}; uint8_t tlen = 6; uint8_t rlen = 0; bus = pal_dev_jtag_gpio_to_bus(slot_id); tbuf[2] = bus; // Read existing FPGA Output pins status. while (retry >= 0) { ret = bic_ipmb_wrapper_with_dev_mux_selection(slot_id, g_dev_id, tbuf[0]>>2, tbuf[1], &tbuf[2], tlen-2, rbuf, &rlen); if (ret == 0) break; retry--; } for (i = 0; i < rlen; i++) { tbuf[6+i] = rbuf[i]; } tlen += (rlen - 1); { tbuf[8] = tbuf[8] & ~3; if (select == 0) { tbuf[8] |= 2; } else { tbuf[8] |= 1; } retry = 5; while (retry >= 0) { ret = bic_ipmb_wrapper_with_dev_mux_selection(slot_id, g_dev_id, tbuf[0]>>2, tbuf[1], &tbuf[2], tlen-2, rbuf, &rlen); if (ret == 0) { break; } retry--; } if (ret) { syslog(LOG_ERR, "%s: BIC no response!\n", __FUNCTION__); return ret; } } return 0; } int tck_mux_select_assert(const int fru, bool assert) { if (fby2_get_slot_type(fru) == SLOT_TYPE_GPV2) { int status = set_sph_mux_command(fru, assert); if (status != 0) { syslog(LOG_ERR, "%s fru=%d triggered : failed to pass command", __FUNCTION__, fru); } } return ST_OK; }