/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "io.h" #ifdef CONFIG_B4860G100 static struct gpiobus gbus; #endif /* CONFIG_B4860G100 */ static inline void byte0_out(unsigned char data); static inline void byte1_out(unsigned char data); static inline void xl_cclk_b(int32_t i); /* Assert and Deassert CCLK */ void xl_shift_cclk(int count) { int i; for (i = 0; i < count; i++) { xl_cclk_b(1); xl_cclk_b(0); } } int xl_supported_prog_bus_width(enum wbus bus_bytes) { switch (bus_bytes) { case bus_1byte: break; case bus_2byte: break; default: pr_err("unsupported program bus width %d\n", bus_bytes); return 0; } return 1; } /* Serialize byte and clock each bit on target's DIN and CCLK pins */ void xl_shift_bytes_out(enum wbus bus_byte, unsigned char *pdata) { /* * supports 1 and 2 bytes programming mode */ if (likely(bus_byte == bus_2byte)) byte0_out(pdata[0]); byte1_out(pdata[1]); xl_shift_cclk(1); } /* * generic bit swap for xilinx SYSTEMMAP FPGA programming */ static inline unsigned char bitswap(unsigned char s) { unsigned char d; d = (((s&0x80)>>7) | ((s&0x40)>>5) | ((s&0x20)>>3) | ((s&0x10)>>1) | ((s&0x08)<<1) | ((s&0x04)<<3) | ((s&0x02)<<5) | ((s&0x01)<<7)); return d; } #ifdef CONFIG_B4860G100 /* * ====================================================================== * board specific configuration */ static inline void mpc85xx_gpio_set_dir( int32_t port, uint32_t mask, uint32_t dir) { dir |= (in_be32(gbus.r[port]+GPDIR) & ~mask); out_be32(gbus.r[port]+GPDIR, dir); } static inline void mpc85xx_gpio_set(int32_t port, uint32_t mask, uint32_t val) { /* First mask off the unwanted parts of "dir" and "val" */ val &= mask; /* Now read in the values we're supposed to preserve */ val |= (in_be32(gbus.r[port]+GPDAT) & ~mask); out_be32(gbus.r[port]+GPDAT, val); } static inline uint32_t mpc85xx_gpio_get(int32_t port, uint32_t mask) { /* Read the requested values */ return in_be32(gbus.r[port]+GPDAT) & mask; } static inline void mpc85xx_gpio_set_low(int32_t port, uint32_t gpios) { mpc85xx_gpio_set(port, gpios, 0x00000000); } static inline void mpc85xx_gpio_set_high(int32_t port, uint32_t gpios) { mpc85xx_gpio_set(port, gpios, 0xFFFFFFFF); } static inline void gpio_set_value(int32_t port, uint32_t gpio, uint32_t value) { int32_t g; g = 31 - gpio; if (value) mpc85xx_gpio_set_high(port, 1U << g); else mpc85xx_gpio_set_low(port, 1U << g); } static inline int gpio_get_value(int32_t port, uint32_t gpio) { int32_t g; g = 31 - gpio; return !!mpc85xx_gpio_get(port, 1U << g); } static inline void xl_cclk_b(int32_t i) { gpio_set_value(XL_CCLK_PORT, XL_CCLK_PIN, i); } void xl_program_b(int32_t i) { gpio_set_value(XL_PROGN_PORT, XL_PROGN_PIN, i); } void xl_rdwr_b(int32_t i) { gpio_set_value(XL_RDWRN_PORT, XL_RDWRN_PIN, i); } void xl_csi_b(int32_t i) { gpio_set_value(XL_CSIN_PORT, XL_CSIN_PIN, i); } int xl_get_init_b(void) { return gpio_get_value(XL_INITN_PORT, XL_INITN_PIN); } int xl_get_done_b(void) { return gpio_get_value(XL_DONE_PORT, XL_DONE_PIN); } /* G100 specific bit swap and remmap (to gpio pins) for byte 0 */ static inline uint32_t bit_remap_byte0(uint32_t s) { uint32_t d; d = (((s&0x80)>>7) | ((s&0x40)>>5) | ((s&0x20)>>3) | ((s&0x10)>>1) | ((s&0x08)<<1) | ((s&0x04)<<3) | ((s&0x02)<<6) | ((s&0x01)<<9)); return d; } /* * G100 specific MSB, in this order [byte0 | byte1], out */ static inline void byte0_out(unsigned char data) { uint32_t swap32; swap32 = bit_remap_byte0((uint32_t) data) << 8; mpc85xx_gpio_set(0, 0x0002BF00, (uint32_t) swap32); } /* * G100 specific LSB, in this order [byte0 | byte1], out */ static inline void byte1_out(unsigned char data) { mpc85xx_gpio_set(0, 0x000000FF, (uint32_t) bitswap(data)); } /* * configurable per device type for different I/O config */ int xl_init_io(void) { struct device_node *np; const u32 *p_reg; int reg, cnt; cnt = 0; memset(&gbus, 0, sizeof(struct gpiobus)); for_each_compatible_node(np, NULL, "fsl,qoriq-gpio") { p_reg = of_get_property(np, "reg", NULL); if (p_reg == NULL) break; reg = (int) *p_reg; gbus.r[cnt] = of_iomap(np, 0); if (!gbus.r[cnt]) { pr_err("not findding gpio cell-index %d\n", cnt); return -ENODEV; } cnt++; } mpc85xx_gpio_set_dir(0, 0x0002BFFF, 0x0002BFFF); mpc85xx_gpio_set_dir(1, 0x00240060, 0x00240060); gbus.ngpio = cnt; return 0; } #else /* placeholder for boards with different config */ void xl_program_b(int32_t i) { return; } void xl_rdwr_b(int32_t i) { return; } void xl_csi_b(int32_t i) { return; } int xl_get_init_b(void) { return -1; } int xl_get_done_b(void) { return -1; } static inline void byte0_out(unsigned char data) { return; } static inline void byte1_out(unsigned char data) { return; } static inline void xl_cclk_b(int32_t i) { return; } /* * configurable per device type for different I/O config */ int xl_init_io(void) { return -1; } #endif /* CONFIG_B4860G100 */