16a794a27SBenjamin Herrenschmidt // SPDX-License-Identifier: GPL-2.0+
26a794a27SBenjamin Herrenschmidt // Copyright 2018 IBM Corp
36a794a27SBenjamin Herrenschmidt /*
46a794a27SBenjamin Herrenschmidt * A FSI master controller, using a simple GPIO bit-banging interface
56a794a27SBenjamin Herrenschmidt */
66a794a27SBenjamin Herrenschmidt
76a794a27SBenjamin Herrenschmidt #include <linux/crc4.h>
86a794a27SBenjamin Herrenschmidt #include <linux/delay.h>
96a794a27SBenjamin Herrenschmidt #include <linux/device.h>
106a794a27SBenjamin Herrenschmidt #include <linux/fsi.h>
116a794a27SBenjamin Herrenschmidt #include <linux/gpio/consumer.h>
126a794a27SBenjamin Herrenschmidt #include <linux/io.h>
136a794a27SBenjamin Herrenschmidt #include <linux/irqflags.h>
146a794a27SBenjamin Herrenschmidt #include <linux/module.h>
156a794a27SBenjamin Herrenschmidt #include <linux/of.h>
166a794a27SBenjamin Herrenschmidt #include <linux/platform_device.h>
176a794a27SBenjamin Herrenschmidt #include <linux/slab.h>
186a794a27SBenjamin Herrenschmidt #include <linux/regmap.h>
196a794a27SBenjamin Herrenschmidt #include <linux/firmware.h>
206a794a27SBenjamin Herrenschmidt #include <linux/gpio/aspeed.h>
216a794a27SBenjamin Herrenschmidt #include <linux/mfd/syscon.h>
226a794a27SBenjamin Herrenschmidt #include <linux/of_address.h>
236a794a27SBenjamin Herrenschmidt #include <linux/genalloc.h>
246a794a27SBenjamin Herrenschmidt
256a794a27SBenjamin Herrenschmidt #include "fsi-master.h"
266a794a27SBenjamin Herrenschmidt #include "cf-fsi-fw.h"
276a794a27SBenjamin Herrenschmidt
286a794a27SBenjamin Herrenschmidt #define FW_FILE_NAME "cf-fsi-fw.bin"
296a794a27SBenjamin Herrenschmidt
306a794a27SBenjamin Herrenschmidt /* Common SCU based coprocessor control registers */
316a794a27SBenjamin Herrenschmidt #define SCU_COPRO_CTRL 0x100
326a794a27SBenjamin Herrenschmidt #define SCU_COPRO_RESET 0x00000002
336a794a27SBenjamin Herrenschmidt #define SCU_COPRO_CLK_EN 0x00000001
346a794a27SBenjamin Herrenschmidt
356a794a27SBenjamin Herrenschmidt /* AST2500 specific ones */
366a794a27SBenjamin Herrenschmidt #define SCU_2500_COPRO_SEG0 0x104
376a794a27SBenjamin Herrenschmidt #define SCU_2500_COPRO_SEG1 0x108
386a794a27SBenjamin Herrenschmidt #define SCU_2500_COPRO_SEG2 0x10c
396a794a27SBenjamin Herrenschmidt #define SCU_2500_COPRO_SEG3 0x110
406a794a27SBenjamin Herrenschmidt #define SCU_2500_COPRO_SEG4 0x114
416a794a27SBenjamin Herrenschmidt #define SCU_2500_COPRO_SEG5 0x118
426a794a27SBenjamin Herrenschmidt #define SCU_2500_COPRO_SEG6 0x11c
436a794a27SBenjamin Herrenschmidt #define SCU_2500_COPRO_SEG7 0x120
446a794a27SBenjamin Herrenschmidt #define SCU_2500_COPRO_SEG8 0x124
456a794a27SBenjamin Herrenschmidt #define SCU_2500_COPRO_SEG_SWAP 0x00000001
466a794a27SBenjamin Herrenschmidt #define SCU_2500_COPRO_CACHE_CTL 0x128
476a794a27SBenjamin Herrenschmidt #define SCU_2500_COPRO_CACHE_EN 0x00000001
486a794a27SBenjamin Herrenschmidt #define SCU_2500_COPRO_SEG0_CACHE_EN 0x00000002
496a794a27SBenjamin Herrenschmidt #define SCU_2500_COPRO_SEG1_CACHE_EN 0x00000004
506a794a27SBenjamin Herrenschmidt #define SCU_2500_COPRO_SEG2_CACHE_EN 0x00000008
516a794a27SBenjamin Herrenschmidt #define SCU_2500_COPRO_SEG3_CACHE_EN 0x00000010
526a794a27SBenjamin Herrenschmidt #define SCU_2500_COPRO_SEG4_CACHE_EN 0x00000020
536a794a27SBenjamin Herrenschmidt #define SCU_2500_COPRO_SEG5_CACHE_EN 0x00000040
546a794a27SBenjamin Herrenschmidt #define SCU_2500_COPRO_SEG6_CACHE_EN 0x00000080
556a794a27SBenjamin Herrenschmidt #define SCU_2500_COPRO_SEG7_CACHE_EN 0x00000100
566a794a27SBenjamin Herrenschmidt #define SCU_2500_COPRO_SEG8_CACHE_EN 0x00000200
576a794a27SBenjamin Herrenschmidt
586a794a27SBenjamin Herrenschmidt #define SCU_2400_COPRO_SEG0 0x104
596a794a27SBenjamin Herrenschmidt #define SCU_2400_COPRO_SEG2 0x108
606a794a27SBenjamin Herrenschmidt #define SCU_2400_COPRO_SEG4 0x10c
616a794a27SBenjamin Herrenschmidt #define SCU_2400_COPRO_SEG6 0x110
626a794a27SBenjamin Herrenschmidt #define SCU_2400_COPRO_SEG8 0x114
636a794a27SBenjamin Herrenschmidt #define SCU_2400_COPRO_SEG_SWAP 0x80000000
646a794a27SBenjamin Herrenschmidt #define SCU_2400_COPRO_CACHE_CTL 0x118
656a794a27SBenjamin Herrenschmidt #define SCU_2400_COPRO_CACHE_EN 0x00000001
666a794a27SBenjamin Herrenschmidt #define SCU_2400_COPRO_SEG0_CACHE_EN 0x00000002
676a794a27SBenjamin Herrenschmidt #define SCU_2400_COPRO_SEG2_CACHE_EN 0x00000004
686a794a27SBenjamin Herrenschmidt #define SCU_2400_COPRO_SEG4_CACHE_EN 0x00000008
696a794a27SBenjamin Herrenschmidt #define SCU_2400_COPRO_SEG6_CACHE_EN 0x00000010
706a794a27SBenjamin Herrenschmidt #define SCU_2400_COPRO_SEG8_CACHE_EN 0x00000020
716a794a27SBenjamin Herrenschmidt
726a794a27SBenjamin Herrenschmidt /* CVIC registers */
736a794a27SBenjamin Herrenschmidt #define CVIC_EN_REG 0x10
746a794a27SBenjamin Herrenschmidt #define CVIC_TRIG_REG 0x18
756a794a27SBenjamin Herrenschmidt
766a794a27SBenjamin Herrenschmidt /*
776a794a27SBenjamin Herrenschmidt * System register base address (needed for configuring the
786a794a27SBenjamin Herrenschmidt * coldfire maps)
796a794a27SBenjamin Herrenschmidt */
806a794a27SBenjamin Herrenschmidt #define SYSREG_BASE 0x1e600000
816a794a27SBenjamin Herrenschmidt
826a794a27SBenjamin Herrenschmidt /* Amount of SRAM required */
836a794a27SBenjamin Herrenschmidt #define SRAM_SIZE 0x1000
846a794a27SBenjamin Herrenschmidt
856a794a27SBenjamin Herrenschmidt #define LAST_ADDR_INVALID 0x1
866a794a27SBenjamin Herrenschmidt
876a794a27SBenjamin Herrenschmidt struct fsi_master_acf {
886a794a27SBenjamin Herrenschmidt struct fsi_master master;
896a794a27SBenjamin Herrenschmidt struct device *dev;
906a794a27SBenjamin Herrenschmidt struct regmap *scu;
916a794a27SBenjamin Herrenschmidt struct mutex lock; /* mutex for command ordering */
926a794a27SBenjamin Herrenschmidt struct gpio_desc *gpio_clk;
936a794a27SBenjamin Herrenschmidt struct gpio_desc *gpio_data;
946a794a27SBenjamin Herrenschmidt struct gpio_desc *gpio_trans; /* Voltage translator */
956a794a27SBenjamin Herrenschmidt struct gpio_desc *gpio_enable; /* FSI enable */
966a794a27SBenjamin Herrenschmidt struct gpio_desc *gpio_mux; /* Mux control */
976a794a27SBenjamin Herrenschmidt uint16_t gpio_clk_vreg;
986a794a27SBenjamin Herrenschmidt uint16_t gpio_clk_dreg;
996a794a27SBenjamin Herrenschmidt uint16_t gpio_dat_vreg;
1006a794a27SBenjamin Herrenschmidt uint16_t gpio_dat_dreg;
1016a794a27SBenjamin Herrenschmidt uint16_t gpio_tra_vreg;
1026a794a27SBenjamin Herrenschmidt uint16_t gpio_tra_dreg;
1036a794a27SBenjamin Herrenschmidt uint8_t gpio_clk_bit;
1046a794a27SBenjamin Herrenschmidt uint8_t gpio_dat_bit;
1056a794a27SBenjamin Herrenschmidt uint8_t gpio_tra_bit;
1066a794a27SBenjamin Herrenschmidt uint32_t cf_mem_addr;
1076a794a27SBenjamin Herrenschmidt size_t cf_mem_size;
1086a794a27SBenjamin Herrenschmidt void __iomem *cf_mem;
1096a794a27SBenjamin Herrenschmidt void __iomem *cvic;
1106a794a27SBenjamin Herrenschmidt struct gen_pool *sram_pool;
1116a794a27SBenjamin Herrenschmidt void __iomem *sram;
1126a794a27SBenjamin Herrenschmidt bool is_ast2500;
1136a794a27SBenjamin Herrenschmidt bool external_mode;
1146a794a27SBenjamin Herrenschmidt bool trace_enabled;
1156a794a27SBenjamin Herrenschmidt uint32_t last_addr;
1166a794a27SBenjamin Herrenschmidt uint8_t t_send_delay;
1176a794a27SBenjamin Herrenschmidt uint8_t t_echo_delay;
1186a794a27SBenjamin Herrenschmidt uint32_t cvic_sw_irq;
1196a794a27SBenjamin Herrenschmidt };
1206a794a27SBenjamin Herrenschmidt #define to_fsi_master_acf(m) container_of(m, struct fsi_master_acf, master)
1216a794a27SBenjamin Herrenschmidt
1226a794a27SBenjamin Herrenschmidt struct fsi_msg {
1236a794a27SBenjamin Herrenschmidt uint64_t msg;
1246a794a27SBenjamin Herrenschmidt uint8_t bits;
1256a794a27SBenjamin Herrenschmidt };
1266a794a27SBenjamin Herrenschmidt
1276a794a27SBenjamin Herrenschmidt #define CREATE_TRACE_POINTS
1286a794a27SBenjamin Herrenschmidt #include <trace/events/fsi_master_ast_cf.h>
1296a794a27SBenjamin Herrenschmidt
msg_push_bits(struct fsi_msg * msg,uint64_t data,int bits)1306a794a27SBenjamin Herrenschmidt static void msg_push_bits(struct fsi_msg *msg, uint64_t data, int bits)
1316a794a27SBenjamin Herrenschmidt {
1326a794a27SBenjamin Herrenschmidt msg->msg <<= bits;
1336a794a27SBenjamin Herrenschmidt msg->msg |= data & ((1ull << bits) - 1);
1346a794a27SBenjamin Herrenschmidt msg->bits += bits;
1356a794a27SBenjamin Herrenschmidt }
1366a794a27SBenjamin Herrenschmidt
msg_push_crc(struct fsi_msg * msg)1376a794a27SBenjamin Herrenschmidt static void msg_push_crc(struct fsi_msg *msg)
1386a794a27SBenjamin Herrenschmidt {
1396a794a27SBenjamin Herrenschmidt uint8_t crc;
1406a794a27SBenjamin Herrenschmidt int top;
1416a794a27SBenjamin Herrenschmidt
1426a794a27SBenjamin Herrenschmidt top = msg->bits & 0x3;
1436a794a27SBenjamin Herrenschmidt
1446a794a27SBenjamin Herrenschmidt /* start bit, and any non-aligned top bits */
1456a794a27SBenjamin Herrenschmidt crc = crc4(0, 1 << top | msg->msg >> (msg->bits - top), top + 1);
1466a794a27SBenjamin Herrenschmidt
1476a794a27SBenjamin Herrenschmidt /* aligned bits */
1486a794a27SBenjamin Herrenschmidt crc = crc4(crc, msg->msg, msg->bits - top);
1496a794a27SBenjamin Herrenschmidt
1506a794a27SBenjamin Herrenschmidt msg_push_bits(msg, crc, 4);
1516a794a27SBenjamin Herrenschmidt }
1526a794a27SBenjamin Herrenschmidt
msg_finish_cmd(struct fsi_msg * cmd)1536a794a27SBenjamin Herrenschmidt static void msg_finish_cmd(struct fsi_msg *cmd)
1546a794a27SBenjamin Herrenschmidt {
1556a794a27SBenjamin Herrenschmidt /* Left align message */
1566a794a27SBenjamin Herrenschmidt cmd->msg <<= (64 - cmd->bits);
1576a794a27SBenjamin Herrenschmidt }
1586a794a27SBenjamin Herrenschmidt
check_same_address(struct fsi_master_acf * master,int id,uint32_t addr)1596a794a27SBenjamin Herrenschmidt static bool check_same_address(struct fsi_master_acf *master, int id,
1606a794a27SBenjamin Herrenschmidt uint32_t addr)
1616a794a27SBenjamin Herrenschmidt {
1626a794a27SBenjamin Herrenschmidt /* this will also handle LAST_ADDR_INVALID */
1636a794a27SBenjamin Herrenschmidt return master->last_addr == (((id & 0x3) << 21) | (addr & ~0x3));
1646a794a27SBenjamin Herrenschmidt }
1656a794a27SBenjamin Herrenschmidt
check_relative_address(struct fsi_master_acf * master,int id,uint32_t addr,uint32_t * rel_addrp)1666a794a27SBenjamin Herrenschmidt static bool check_relative_address(struct fsi_master_acf *master, int id,
1676a794a27SBenjamin Herrenschmidt uint32_t addr, uint32_t *rel_addrp)
1686a794a27SBenjamin Herrenschmidt {
1696a794a27SBenjamin Herrenschmidt uint32_t last_addr = master->last_addr;
1706a794a27SBenjamin Herrenschmidt int32_t rel_addr;
1716a794a27SBenjamin Herrenschmidt
1726a794a27SBenjamin Herrenschmidt if (last_addr == LAST_ADDR_INVALID)
1736a794a27SBenjamin Herrenschmidt return false;
1746a794a27SBenjamin Herrenschmidt
1756a794a27SBenjamin Herrenschmidt /* We may be in 23-bit addressing mode, which uses the id as the
1766a794a27SBenjamin Herrenschmidt * top two address bits. So, if we're referencing a different ID,
1776a794a27SBenjamin Herrenschmidt * use absolute addresses.
1786a794a27SBenjamin Herrenschmidt */
1796a794a27SBenjamin Herrenschmidt if (((last_addr >> 21) & 0x3) != id)
1806a794a27SBenjamin Herrenschmidt return false;
1816a794a27SBenjamin Herrenschmidt
1826a794a27SBenjamin Herrenschmidt /* remove the top two bits from any 23-bit addressing */
1836a794a27SBenjamin Herrenschmidt last_addr &= (1 << 21) - 1;
1846a794a27SBenjamin Herrenschmidt
1856a794a27SBenjamin Herrenschmidt /* We know that the addresses are limited to 21 bits, so this won't
1866a794a27SBenjamin Herrenschmidt * overflow the signed rel_addr */
1876a794a27SBenjamin Herrenschmidt rel_addr = addr - last_addr;
1886a794a27SBenjamin Herrenschmidt if (rel_addr > 255 || rel_addr < -256)
1896a794a27SBenjamin Herrenschmidt return false;
1906a794a27SBenjamin Herrenschmidt
1916a794a27SBenjamin Herrenschmidt *rel_addrp = (uint32_t)rel_addr;
1926a794a27SBenjamin Herrenschmidt
1936a794a27SBenjamin Herrenschmidt return true;
1946a794a27SBenjamin Herrenschmidt }
1956a794a27SBenjamin Herrenschmidt
last_address_update(struct fsi_master_acf * master,int id,bool valid,uint32_t addr)1966a794a27SBenjamin Herrenschmidt static void last_address_update(struct fsi_master_acf *master,
1976a794a27SBenjamin Herrenschmidt int id, bool valid, uint32_t addr)
1986a794a27SBenjamin Herrenschmidt {
1996a794a27SBenjamin Herrenschmidt if (!valid)
2006a794a27SBenjamin Herrenschmidt master->last_addr = LAST_ADDR_INVALID;
2016a794a27SBenjamin Herrenschmidt else
2026a794a27SBenjamin Herrenschmidt master->last_addr = ((id & 0x3) << 21) | (addr & ~0x3);
2036a794a27SBenjamin Herrenschmidt }
2046a794a27SBenjamin Herrenschmidt
2056a794a27SBenjamin Herrenschmidt /*
2066a794a27SBenjamin Herrenschmidt * Encode an Absolute/Relative/Same Address command
2076a794a27SBenjamin Herrenschmidt */
build_ar_command(struct fsi_master_acf * master,struct fsi_msg * cmd,uint8_t id,uint32_t addr,size_t size,const void * data)2086a794a27SBenjamin Herrenschmidt static void build_ar_command(struct fsi_master_acf *master,
2096a794a27SBenjamin Herrenschmidt struct fsi_msg *cmd, uint8_t id,
2106a794a27SBenjamin Herrenschmidt uint32_t addr, size_t size,
2116a794a27SBenjamin Herrenschmidt const void *data)
2126a794a27SBenjamin Herrenschmidt {
2136a794a27SBenjamin Herrenschmidt int i, addr_bits, opcode_bits;
2146a794a27SBenjamin Herrenschmidt bool write = !!data;
2156a794a27SBenjamin Herrenschmidt uint8_t ds, opcode;
2166a794a27SBenjamin Herrenschmidt uint32_t rel_addr;
2176a794a27SBenjamin Herrenschmidt
2186a794a27SBenjamin Herrenschmidt cmd->bits = 0;
2196a794a27SBenjamin Herrenschmidt cmd->msg = 0;
2206a794a27SBenjamin Herrenschmidt
2216a794a27SBenjamin Herrenschmidt /* we have 21 bits of address max */
2226a794a27SBenjamin Herrenschmidt addr &= ((1 << 21) - 1);
2236a794a27SBenjamin Herrenschmidt
2246a794a27SBenjamin Herrenschmidt /* cmd opcodes are variable length - SAME_AR is only two bits */
2256a794a27SBenjamin Herrenschmidt opcode_bits = 3;
2266a794a27SBenjamin Herrenschmidt
2276a794a27SBenjamin Herrenschmidt if (check_same_address(master, id, addr)) {
2286a794a27SBenjamin Herrenschmidt /* we still address the byte offset within the word */
2296a794a27SBenjamin Herrenschmidt addr_bits = 2;
2306a794a27SBenjamin Herrenschmidt opcode_bits = 2;
2316a794a27SBenjamin Herrenschmidt opcode = FSI_CMD_SAME_AR;
2326a794a27SBenjamin Herrenschmidt trace_fsi_master_acf_cmd_same_addr(master);
2336a794a27SBenjamin Herrenschmidt
2346a794a27SBenjamin Herrenschmidt } else if (check_relative_address(master, id, addr, &rel_addr)) {
2356a794a27SBenjamin Herrenschmidt /* 8 bits plus sign */
2366a794a27SBenjamin Herrenschmidt addr_bits = 9;
2376a794a27SBenjamin Herrenschmidt addr = rel_addr;
2386a794a27SBenjamin Herrenschmidt opcode = FSI_CMD_REL_AR;
2396a794a27SBenjamin Herrenschmidt trace_fsi_master_acf_cmd_rel_addr(master, rel_addr);
2406a794a27SBenjamin Herrenschmidt
2416a794a27SBenjamin Herrenschmidt } else {
2426a794a27SBenjamin Herrenschmidt addr_bits = 21;
2436a794a27SBenjamin Herrenschmidt opcode = FSI_CMD_ABS_AR;
2446a794a27SBenjamin Herrenschmidt trace_fsi_master_acf_cmd_abs_addr(master, addr);
2456a794a27SBenjamin Herrenschmidt }
2466a794a27SBenjamin Herrenschmidt
2476a794a27SBenjamin Herrenschmidt /*
2486a794a27SBenjamin Herrenschmidt * The read/write size is encoded in the lower bits of the address
2496a794a27SBenjamin Herrenschmidt * (as it must be naturally-aligned), and the following ds bit.
2506a794a27SBenjamin Herrenschmidt *
2516a794a27SBenjamin Herrenschmidt * size addr:1 addr:0 ds
2526a794a27SBenjamin Herrenschmidt * 1 x x 0
2536a794a27SBenjamin Herrenschmidt * 2 x 0 1
2546a794a27SBenjamin Herrenschmidt * 4 0 1 1
2556a794a27SBenjamin Herrenschmidt *
2566a794a27SBenjamin Herrenschmidt */
2576a794a27SBenjamin Herrenschmidt ds = size > 1 ? 1 : 0;
2586a794a27SBenjamin Herrenschmidt addr &= ~(size - 1);
2596a794a27SBenjamin Herrenschmidt if (size == 4)
2606a794a27SBenjamin Herrenschmidt addr |= 1;
2616a794a27SBenjamin Herrenschmidt
2626a794a27SBenjamin Herrenschmidt msg_push_bits(cmd, id, 2);
2636a794a27SBenjamin Herrenschmidt msg_push_bits(cmd, opcode, opcode_bits);
2646a794a27SBenjamin Herrenschmidt msg_push_bits(cmd, write ? 0 : 1, 1);
2656a794a27SBenjamin Herrenschmidt msg_push_bits(cmd, addr, addr_bits);
2666a794a27SBenjamin Herrenschmidt msg_push_bits(cmd, ds, 1);
2676a794a27SBenjamin Herrenschmidt for (i = 0; write && i < size; i++)
2686a794a27SBenjamin Herrenschmidt msg_push_bits(cmd, ((uint8_t *)data)[i], 8);
2696a794a27SBenjamin Herrenschmidt
2706a794a27SBenjamin Herrenschmidt msg_push_crc(cmd);
2716a794a27SBenjamin Herrenschmidt msg_finish_cmd(cmd);
2726a794a27SBenjamin Herrenschmidt }
2736a794a27SBenjamin Herrenschmidt
build_dpoll_command(struct fsi_msg * cmd,uint8_t slave_id)2746a794a27SBenjamin Herrenschmidt static void build_dpoll_command(struct fsi_msg *cmd, uint8_t slave_id)
2756a794a27SBenjamin Herrenschmidt {
2766a794a27SBenjamin Herrenschmidt cmd->bits = 0;
2776a794a27SBenjamin Herrenschmidt cmd->msg = 0;
2786a794a27SBenjamin Herrenschmidt
2796a794a27SBenjamin Herrenschmidt msg_push_bits(cmd, slave_id, 2);
2806a794a27SBenjamin Herrenschmidt msg_push_bits(cmd, FSI_CMD_DPOLL, 3);
2816a794a27SBenjamin Herrenschmidt msg_push_crc(cmd);
2826a794a27SBenjamin Herrenschmidt msg_finish_cmd(cmd);
2836a794a27SBenjamin Herrenschmidt }
2846a794a27SBenjamin Herrenschmidt
build_epoll_command(struct fsi_msg * cmd,uint8_t slave_id)2856a794a27SBenjamin Herrenschmidt static void build_epoll_command(struct fsi_msg *cmd, uint8_t slave_id)
2866a794a27SBenjamin Herrenschmidt {
2876a794a27SBenjamin Herrenschmidt cmd->bits = 0;
2886a794a27SBenjamin Herrenschmidt cmd->msg = 0;
2896a794a27SBenjamin Herrenschmidt
2906a794a27SBenjamin Herrenschmidt msg_push_bits(cmd, slave_id, 2);
2916a794a27SBenjamin Herrenschmidt msg_push_bits(cmd, FSI_CMD_EPOLL, 3);
2926a794a27SBenjamin Herrenschmidt msg_push_crc(cmd);
2936a794a27SBenjamin Herrenschmidt msg_finish_cmd(cmd);
2946a794a27SBenjamin Herrenschmidt }
2956a794a27SBenjamin Herrenschmidt
build_term_command(struct fsi_msg * cmd,uint8_t slave_id)2966a794a27SBenjamin Herrenschmidt static void build_term_command(struct fsi_msg *cmd, uint8_t slave_id)
2976a794a27SBenjamin Herrenschmidt {
2986a794a27SBenjamin Herrenschmidt cmd->bits = 0;
2996a794a27SBenjamin Herrenschmidt cmd->msg = 0;
3006a794a27SBenjamin Herrenschmidt
3016a794a27SBenjamin Herrenschmidt msg_push_bits(cmd, slave_id, 2);
3026a794a27SBenjamin Herrenschmidt msg_push_bits(cmd, FSI_CMD_TERM, 6);
3036a794a27SBenjamin Herrenschmidt msg_push_crc(cmd);
3046a794a27SBenjamin Herrenschmidt msg_finish_cmd(cmd);
3056a794a27SBenjamin Herrenschmidt }
3066a794a27SBenjamin Herrenschmidt
do_copro_command(struct fsi_master_acf * master,uint32_t op)3076a794a27SBenjamin Herrenschmidt static int do_copro_command(struct fsi_master_acf *master, uint32_t op)
3086a794a27SBenjamin Herrenschmidt {
3096a794a27SBenjamin Herrenschmidt uint32_t timeout = 10000000;
3106a794a27SBenjamin Herrenschmidt uint8_t stat;
3116a794a27SBenjamin Herrenschmidt
3126a794a27SBenjamin Herrenschmidt trace_fsi_master_acf_copro_command(master, op);
3136a794a27SBenjamin Herrenschmidt
3146a794a27SBenjamin Herrenschmidt /* Send command */
3156a794a27SBenjamin Herrenschmidt iowrite32be(op, master->sram + CMD_STAT_REG);
3166a794a27SBenjamin Herrenschmidt
3176a794a27SBenjamin Herrenschmidt /* Ring doorbell if any */
3186a794a27SBenjamin Herrenschmidt if (master->cvic)
3196a794a27SBenjamin Herrenschmidt iowrite32(0x2, master->cvic + CVIC_TRIG_REG);
3206a794a27SBenjamin Herrenschmidt
3216a794a27SBenjamin Herrenschmidt /* Wait for status to indicate completion (or error) */
3226a794a27SBenjamin Herrenschmidt do {
3236a794a27SBenjamin Herrenschmidt if (timeout-- == 0) {
3246a794a27SBenjamin Herrenschmidt dev_warn(master->dev,
3256a794a27SBenjamin Herrenschmidt "Timeout waiting for coprocessor completion\n");
3266a794a27SBenjamin Herrenschmidt return -ETIMEDOUT;
3276a794a27SBenjamin Herrenschmidt }
3286a794a27SBenjamin Herrenschmidt stat = ioread8(master->sram + CMD_STAT_REG);
3296a794a27SBenjamin Herrenschmidt } while(stat < STAT_COMPLETE || stat == 0xff);
3306a794a27SBenjamin Herrenschmidt
3316a794a27SBenjamin Herrenschmidt if (stat == STAT_COMPLETE)
3326a794a27SBenjamin Herrenschmidt return 0;
3336a794a27SBenjamin Herrenschmidt switch(stat) {
3346a794a27SBenjamin Herrenschmidt case STAT_ERR_INVAL_CMD:
3356a794a27SBenjamin Herrenschmidt return -EINVAL;
3366a794a27SBenjamin Herrenschmidt case STAT_ERR_INVAL_IRQ:
3376a794a27SBenjamin Herrenschmidt return -EIO;
3386a794a27SBenjamin Herrenschmidt case STAT_ERR_MTOE:
3396a794a27SBenjamin Herrenschmidt return -ESHUTDOWN;
3406a794a27SBenjamin Herrenschmidt }
3416a794a27SBenjamin Herrenschmidt return -ENXIO;
3426a794a27SBenjamin Herrenschmidt }
3436a794a27SBenjamin Herrenschmidt
clock_zeros(struct fsi_master_acf * master,int count)3446a794a27SBenjamin Herrenschmidt static int clock_zeros(struct fsi_master_acf *master, int count)
3456a794a27SBenjamin Herrenschmidt {
3466a794a27SBenjamin Herrenschmidt while (count) {
3476a794a27SBenjamin Herrenschmidt int rc, lcnt = min(count, 255);
3486a794a27SBenjamin Herrenschmidt
3496a794a27SBenjamin Herrenschmidt rc = do_copro_command(master,
3506a794a27SBenjamin Herrenschmidt CMD_IDLE_CLOCKS | (lcnt << CMD_REG_CLEN_SHIFT));
3516a794a27SBenjamin Herrenschmidt if (rc)
3526a794a27SBenjamin Herrenschmidt return rc;
3536a794a27SBenjamin Herrenschmidt count -= lcnt;
3546a794a27SBenjamin Herrenschmidt }
3556a794a27SBenjamin Herrenschmidt return 0;
3566a794a27SBenjamin Herrenschmidt }
3576a794a27SBenjamin Herrenschmidt
send_request(struct fsi_master_acf * master,struct fsi_msg * cmd,unsigned int resp_bits)3586a794a27SBenjamin Herrenschmidt static int send_request(struct fsi_master_acf *master, struct fsi_msg *cmd,
3596a794a27SBenjamin Herrenschmidt unsigned int resp_bits)
3606a794a27SBenjamin Herrenschmidt {
3616a794a27SBenjamin Herrenschmidt uint32_t op;
3626a794a27SBenjamin Herrenschmidt
3636a794a27SBenjamin Herrenschmidt trace_fsi_master_acf_send_request(master, cmd, resp_bits);
3646a794a27SBenjamin Herrenschmidt
3656a794a27SBenjamin Herrenschmidt /* Store message into SRAM */
3666a794a27SBenjamin Herrenschmidt iowrite32be((cmd->msg >> 32), master->sram + CMD_DATA);
3676a794a27SBenjamin Herrenschmidt iowrite32be((cmd->msg & 0xffffffff), master->sram + CMD_DATA + 4);
3686a794a27SBenjamin Herrenschmidt
3696a794a27SBenjamin Herrenschmidt op = CMD_COMMAND;
3706a794a27SBenjamin Herrenschmidt op |= cmd->bits << CMD_REG_CLEN_SHIFT;
3716a794a27SBenjamin Herrenschmidt if (resp_bits)
3726a794a27SBenjamin Herrenschmidt op |= resp_bits << CMD_REG_RLEN_SHIFT;
3736a794a27SBenjamin Herrenschmidt
3746a794a27SBenjamin Herrenschmidt return do_copro_command(master, op);
3756a794a27SBenjamin Herrenschmidt }
3766a794a27SBenjamin Herrenschmidt
read_copro_response(struct fsi_master_acf * master,uint8_t size,uint32_t * response,u8 * tag)3776a794a27SBenjamin Herrenschmidt static int read_copro_response(struct fsi_master_acf *master, uint8_t size,
3786a794a27SBenjamin Herrenschmidt uint32_t *response, u8 *tag)
3796a794a27SBenjamin Herrenschmidt {
380375cac70SBenjamin Herrenschmidt uint8_t rtag = ioread8(master->sram + STAT_RTAG) & 0xf;
381375cac70SBenjamin Herrenschmidt uint8_t rcrc = ioread8(master->sram + STAT_RCRC) & 0xf;
3826a794a27SBenjamin Herrenschmidt uint32_t rdata = 0;
3836a794a27SBenjamin Herrenschmidt uint32_t crc;
3846a794a27SBenjamin Herrenschmidt uint8_t ack;
3856a794a27SBenjamin Herrenschmidt
3866a794a27SBenjamin Herrenschmidt *tag = ack = rtag & 3;
3876a794a27SBenjamin Herrenschmidt
3886a794a27SBenjamin Herrenschmidt /* we have a whole message now; check CRC */
3896a794a27SBenjamin Herrenschmidt crc = crc4(0, 1, 1);
3906a794a27SBenjamin Herrenschmidt crc = crc4(crc, rtag, 4);
3916a794a27SBenjamin Herrenschmidt if (ack == FSI_RESP_ACK && size) {
3926a794a27SBenjamin Herrenschmidt rdata = ioread32be(master->sram + RSP_DATA);
3936a794a27SBenjamin Herrenschmidt crc = crc4(crc, rdata, size);
3946a794a27SBenjamin Herrenschmidt if (response)
3956a794a27SBenjamin Herrenschmidt *response = rdata;
3966a794a27SBenjamin Herrenschmidt }
3976a794a27SBenjamin Herrenschmidt crc = crc4(crc, rcrc, 4);
3986a794a27SBenjamin Herrenschmidt
3996a794a27SBenjamin Herrenschmidt trace_fsi_master_acf_copro_response(master, rtag, rcrc, rdata, crc == 0);
4006a794a27SBenjamin Herrenschmidt
4016a794a27SBenjamin Herrenschmidt if (crc) {
4026a794a27SBenjamin Herrenschmidt /*
4036a794a27SBenjamin Herrenschmidt * Check if it's all 1's or all 0's, that probably means
4046a794a27SBenjamin Herrenschmidt * the host is off
4056a794a27SBenjamin Herrenschmidt */
4066a794a27SBenjamin Herrenschmidt if ((rtag == 0xf && rcrc == 0xf) || (rtag == 0 && rcrc == 0))
4076a794a27SBenjamin Herrenschmidt return -ENODEV;
4086a794a27SBenjamin Herrenschmidt dev_dbg(master->dev, "Bad response CRC !\n");
4096a794a27SBenjamin Herrenschmidt return -EAGAIN;
4106a794a27SBenjamin Herrenschmidt }
4116a794a27SBenjamin Herrenschmidt return 0;
4126a794a27SBenjamin Herrenschmidt }
4136a794a27SBenjamin Herrenschmidt
send_term(struct fsi_master_acf * master,uint8_t slave)4146a794a27SBenjamin Herrenschmidt static int send_term(struct fsi_master_acf *master, uint8_t slave)
4156a794a27SBenjamin Herrenschmidt {
4166a794a27SBenjamin Herrenschmidt struct fsi_msg cmd;
4176a794a27SBenjamin Herrenschmidt uint8_t tag;
4186a794a27SBenjamin Herrenschmidt int rc;
4196a794a27SBenjamin Herrenschmidt
4206a794a27SBenjamin Herrenschmidt build_term_command(&cmd, slave);
4216a794a27SBenjamin Herrenschmidt
4226a794a27SBenjamin Herrenschmidt rc = send_request(master, &cmd, 0);
4236a794a27SBenjamin Herrenschmidt if (rc) {
4246a794a27SBenjamin Herrenschmidt dev_warn(master->dev, "Error %d sending term\n", rc);
4256a794a27SBenjamin Herrenschmidt return rc;
4266a794a27SBenjamin Herrenschmidt }
4276a794a27SBenjamin Herrenschmidt
4286a794a27SBenjamin Herrenschmidt rc = read_copro_response(master, 0, NULL, &tag);
4296a794a27SBenjamin Herrenschmidt if (rc < 0) {
4306a794a27SBenjamin Herrenschmidt dev_err(master->dev,
4316a794a27SBenjamin Herrenschmidt "TERM failed; lost communication with slave\n");
4326a794a27SBenjamin Herrenschmidt return -EIO;
4336a794a27SBenjamin Herrenschmidt } else if (tag != FSI_RESP_ACK) {
4346a794a27SBenjamin Herrenschmidt dev_err(master->dev, "TERM failed; response %d\n", tag);
4356a794a27SBenjamin Herrenschmidt return -EIO;
4366a794a27SBenjamin Herrenschmidt }
4376a794a27SBenjamin Herrenschmidt return 0;
4386a794a27SBenjamin Herrenschmidt }
4396a794a27SBenjamin Herrenschmidt
dump_ucode_trace(struct fsi_master_acf * master)440537052dfSBenjamin Herrenschmidt static void dump_ucode_trace(struct fsi_master_acf *master)
4416a794a27SBenjamin Herrenschmidt {
4426a794a27SBenjamin Herrenschmidt char trbuf[52];
4436a794a27SBenjamin Herrenschmidt char *p;
4446a794a27SBenjamin Herrenschmidt int i;
4456a794a27SBenjamin Herrenschmidt
4466a794a27SBenjamin Herrenschmidt dev_dbg(master->dev,
4476a794a27SBenjamin Herrenschmidt "CMDSTAT:%08x RTAG=%02x RCRC=%02x RDATA=%02x #INT=%08x\n",
4486a794a27SBenjamin Herrenschmidt ioread32be(master->sram + CMD_STAT_REG),
4496a794a27SBenjamin Herrenschmidt ioread8(master->sram + STAT_RTAG),
4506a794a27SBenjamin Herrenschmidt ioread8(master->sram + STAT_RCRC),
4516a794a27SBenjamin Herrenschmidt ioread32be(master->sram + RSP_DATA),
4526a794a27SBenjamin Herrenschmidt ioread32be(master->sram + INT_CNT));
4536a794a27SBenjamin Herrenschmidt
4546a794a27SBenjamin Herrenschmidt for (i = 0; i < 512; i++) {
4556a794a27SBenjamin Herrenschmidt uint8_t v;
4566a794a27SBenjamin Herrenschmidt if ((i % 16) == 0)
4576a794a27SBenjamin Herrenschmidt p = trbuf;
4586a794a27SBenjamin Herrenschmidt v = ioread8(master->sram + TRACEBUF + i);
4596a794a27SBenjamin Herrenschmidt p += sprintf(p, "%02x ", v);
4606a794a27SBenjamin Herrenschmidt if (((i % 16) == 15) || v == TR_END)
4616a794a27SBenjamin Herrenschmidt dev_dbg(master->dev, "%s\n", trbuf);
4626a794a27SBenjamin Herrenschmidt if (v == TR_END)
4636a794a27SBenjamin Herrenschmidt break;
4646a794a27SBenjamin Herrenschmidt }
4656a794a27SBenjamin Herrenschmidt }
4666a794a27SBenjamin Herrenschmidt
handle_response(struct fsi_master_acf * master,uint8_t slave,uint8_t size,void * data)4676a794a27SBenjamin Herrenschmidt static int handle_response(struct fsi_master_acf *master,
4686a794a27SBenjamin Herrenschmidt uint8_t slave, uint8_t size, void *data)
4696a794a27SBenjamin Herrenschmidt {
4706a794a27SBenjamin Herrenschmidt int busy_count = 0, rc;
4716a794a27SBenjamin Herrenschmidt int crc_err_retries = 0;
4726a794a27SBenjamin Herrenschmidt struct fsi_msg cmd;
4736a794a27SBenjamin Herrenschmidt uint32_t response;
4746a794a27SBenjamin Herrenschmidt uint8_t tag;
4756a794a27SBenjamin Herrenschmidt retry:
4766a794a27SBenjamin Herrenschmidt rc = read_copro_response(master, size, &response, &tag);
4776a794a27SBenjamin Herrenschmidt
4786a794a27SBenjamin Herrenschmidt /* Handle retries on CRC errors */
4796a794a27SBenjamin Herrenschmidt if (rc == -EAGAIN) {
4806a794a27SBenjamin Herrenschmidt /* Too many retries ? */
4816a794a27SBenjamin Herrenschmidt if (crc_err_retries++ > FSI_CRC_ERR_RETRIES) {
4826a794a27SBenjamin Herrenschmidt /*
4836a794a27SBenjamin Herrenschmidt * Pass it up as a -EIO otherwise upper level will retry
4846a794a27SBenjamin Herrenschmidt * the whole command which isn't what we want here.
4856a794a27SBenjamin Herrenschmidt */
4866a794a27SBenjamin Herrenschmidt rc = -EIO;
4876a794a27SBenjamin Herrenschmidt goto bail;
4886a794a27SBenjamin Herrenschmidt }
4896a794a27SBenjamin Herrenschmidt trace_fsi_master_acf_crc_rsp_error(master, crc_err_retries);
4906a794a27SBenjamin Herrenschmidt if (master->trace_enabled)
491537052dfSBenjamin Herrenschmidt dump_ucode_trace(master);
4926a794a27SBenjamin Herrenschmidt rc = clock_zeros(master, FSI_MASTER_EPOLL_CLOCKS);
4936a794a27SBenjamin Herrenschmidt if (rc) {
4946a794a27SBenjamin Herrenschmidt dev_warn(master->dev,
4956a794a27SBenjamin Herrenschmidt "Error %d clocking zeros for E_POLL\n", rc);
4966a794a27SBenjamin Herrenschmidt return rc;
4976a794a27SBenjamin Herrenschmidt }
4986a794a27SBenjamin Herrenschmidt build_epoll_command(&cmd, slave);
4996a794a27SBenjamin Herrenschmidt rc = send_request(master, &cmd, size);
5006a794a27SBenjamin Herrenschmidt if (rc) {
5016a794a27SBenjamin Herrenschmidt dev_warn(master->dev, "Error %d sending E_POLL\n", rc);
5026a794a27SBenjamin Herrenschmidt return -EIO;
5036a794a27SBenjamin Herrenschmidt }
5046a794a27SBenjamin Herrenschmidt goto retry;
5056a794a27SBenjamin Herrenschmidt }
5066a794a27SBenjamin Herrenschmidt if (rc)
5076a794a27SBenjamin Herrenschmidt return rc;
5086a794a27SBenjamin Herrenschmidt
5096a794a27SBenjamin Herrenschmidt switch (tag) {
5106a794a27SBenjamin Herrenschmidt case FSI_RESP_ACK:
5116a794a27SBenjamin Herrenschmidt if (size && data) {
5126a794a27SBenjamin Herrenschmidt if (size == 32)
5136a794a27SBenjamin Herrenschmidt *(__be32 *)data = cpu_to_be32(response);
5146a794a27SBenjamin Herrenschmidt else if (size == 16)
5156a794a27SBenjamin Herrenschmidt *(__be16 *)data = cpu_to_be16(response);
5166a794a27SBenjamin Herrenschmidt else
5176a794a27SBenjamin Herrenschmidt *(u8 *)data = response;
5186a794a27SBenjamin Herrenschmidt }
5196a794a27SBenjamin Herrenschmidt break;
5206a794a27SBenjamin Herrenschmidt case FSI_RESP_BUSY:
5216a794a27SBenjamin Herrenschmidt /*
5226a794a27SBenjamin Herrenschmidt * Its necessary to clock slave before issuing
5236a794a27SBenjamin Herrenschmidt * d-poll, not indicated in the hardware protocol
5246a794a27SBenjamin Herrenschmidt * spec. < 20 clocks causes slave to hang, 21 ok.
5256a794a27SBenjamin Herrenschmidt */
5266a794a27SBenjamin Herrenschmidt dev_dbg(master->dev, "Busy, retrying...\n");
5276a794a27SBenjamin Herrenschmidt if (master->trace_enabled)
528537052dfSBenjamin Herrenschmidt dump_ucode_trace(master);
5296a794a27SBenjamin Herrenschmidt rc = clock_zeros(master, FSI_MASTER_DPOLL_CLOCKS);
5306a794a27SBenjamin Herrenschmidt if (rc) {
5316a794a27SBenjamin Herrenschmidt dev_warn(master->dev,
5326a794a27SBenjamin Herrenschmidt "Error %d clocking zeros for D_POLL\n", rc);
5336a794a27SBenjamin Herrenschmidt break;
5346a794a27SBenjamin Herrenschmidt }
5356a794a27SBenjamin Herrenschmidt if (busy_count++ < FSI_MASTER_MAX_BUSY) {
5366a794a27SBenjamin Herrenschmidt build_dpoll_command(&cmd, slave);
5376a794a27SBenjamin Herrenschmidt rc = send_request(master, &cmd, size);
5386a794a27SBenjamin Herrenschmidt if (rc) {
5396a794a27SBenjamin Herrenschmidt dev_warn(master->dev, "Error %d sending D_POLL\n", rc);
5406a794a27SBenjamin Herrenschmidt break;
5416a794a27SBenjamin Herrenschmidt }
5426a794a27SBenjamin Herrenschmidt goto retry;
5436a794a27SBenjamin Herrenschmidt }
5446a794a27SBenjamin Herrenschmidt dev_dbg(master->dev,
5456a794a27SBenjamin Herrenschmidt "ERR slave is stuck in busy state, issuing TERM\n");
5466a794a27SBenjamin Herrenschmidt send_term(master, slave);
5476a794a27SBenjamin Herrenschmidt rc = -EIO;
5486a794a27SBenjamin Herrenschmidt break;
5496a794a27SBenjamin Herrenschmidt
5506a794a27SBenjamin Herrenschmidt case FSI_RESP_ERRA:
5516a794a27SBenjamin Herrenschmidt dev_dbg(master->dev, "ERRA received\n");
5526a794a27SBenjamin Herrenschmidt if (master->trace_enabled)
553537052dfSBenjamin Herrenschmidt dump_ucode_trace(master);
5546a794a27SBenjamin Herrenschmidt rc = -EIO;
5556a794a27SBenjamin Herrenschmidt break;
5566a794a27SBenjamin Herrenschmidt case FSI_RESP_ERRC:
5576a794a27SBenjamin Herrenschmidt dev_dbg(master->dev, "ERRC received\n");
5586a794a27SBenjamin Herrenschmidt if (master->trace_enabled)
559537052dfSBenjamin Herrenschmidt dump_ucode_trace(master);
5606a794a27SBenjamin Herrenschmidt rc = -EAGAIN;
5616a794a27SBenjamin Herrenschmidt break;
5626a794a27SBenjamin Herrenschmidt }
5636a794a27SBenjamin Herrenschmidt bail:
5646a794a27SBenjamin Herrenschmidt if (busy_count > 0) {
5656a794a27SBenjamin Herrenschmidt trace_fsi_master_acf_poll_response_busy(master, busy_count);
5666a794a27SBenjamin Herrenschmidt }
5676a794a27SBenjamin Herrenschmidt
5686a794a27SBenjamin Herrenschmidt return rc;
5696a794a27SBenjamin Herrenschmidt }
5706a794a27SBenjamin Herrenschmidt
fsi_master_acf_xfer(struct fsi_master_acf * master,uint8_t slave,struct fsi_msg * cmd,size_t resp_len,void * resp)5716a794a27SBenjamin Herrenschmidt static int fsi_master_acf_xfer(struct fsi_master_acf *master, uint8_t slave,
5726a794a27SBenjamin Herrenschmidt struct fsi_msg *cmd, size_t resp_len, void *resp)
5736a794a27SBenjamin Herrenschmidt {
5746a794a27SBenjamin Herrenschmidt int rc = -EAGAIN, retries = 0;
5756a794a27SBenjamin Herrenschmidt
5766a794a27SBenjamin Herrenschmidt resp_len <<= 3;
5776a794a27SBenjamin Herrenschmidt while ((retries++) < FSI_CRC_ERR_RETRIES) {
5786a794a27SBenjamin Herrenschmidt rc = send_request(master, cmd, resp_len);
5796a794a27SBenjamin Herrenschmidt if (rc) {
5806a794a27SBenjamin Herrenschmidt if (rc != -ESHUTDOWN)
5816a794a27SBenjamin Herrenschmidt dev_warn(master->dev, "Error %d sending command\n", rc);
5826a794a27SBenjamin Herrenschmidt break;
5836a794a27SBenjamin Herrenschmidt }
5846a794a27SBenjamin Herrenschmidt rc = handle_response(master, slave, resp_len, resp);
5856a794a27SBenjamin Herrenschmidt if (rc != -EAGAIN)
5866a794a27SBenjamin Herrenschmidt break;
5876a794a27SBenjamin Herrenschmidt rc = -EIO;
5886a794a27SBenjamin Herrenschmidt dev_dbg(master->dev, "ECRC retry %d\n", retries);
5896a794a27SBenjamin Herrenschmidt
5906a794a27SBenjamin Herrenschmidt /* Pace it a bit before retry */
5916a794a27SBenjamin Herrenschmidt msleep(1);
5926a794a27SBenjamin Herrenschmidt }
5936a794a27SBenjamin Herrenschmidt
5946a794a27SBenjamin Herrenschmidt return rc;
5956a794a27SBenjamin Herrenschmidt }
5966a794a27SBenjamin Herrenschmidt
fsi_master_acf_read(struct fsi_master * _master,int link,uint8_t id,uint32_t addr,void * val,size_t size)5976a794a27SBenjamin Herrenschmidt static int fsi_master_acf_read(struct fsi_master *_master, int link,
5986a794a27SBenjamin Herrenschmidt uint8_t id, uint32_t addr, void *val,
5996a794a27SBenjamin Herrenschmidt size_t size)
6006a794a27SBenjamin Herrenschmidt {
6016a794a27SBenjamin Herrenschmidt struct fsi_master_acf *master = to_fsi_master_acf(_master);
6026a794a27SBenjamin Herrenschmidt struct fsi_msg cmd;
6036a794a27SBenjamin Herrenschmidt int rc;
6046a794a27SBenjamin Herrenschmidt
6056a794a27SBenjamin Herrenschmidt if (link != 0)
6066a794a27SBenjamin Herrenschmidt return -ENODEV;
6076a794a27SBenjamin Herrenschmidt
6086a794a27SBenjamin Herrenschmidt mutex_lock(&master->lock);
609d0cff240SBenjamin Herrenschmidt dev_dbg(master->dev, "read id %d addr %x size %zd\n", id, addr, size);
6106a794a27SBenjamin Herrenschmidt build_ar_command(master, &cmd, id, addr, size, NULL);
6116a794a27SBenjamin Herrenschmidt rc = fsi_master_acf_xfer(master, id, &cmd, size, val);
6126a794a27SBenjamin Herrenschmidt last_address_update(master, id, rc == 0, addr);
6136a794a27SBenjamin Herrenschmidt if (rc)
6146a794a27SBenjamin Herrenschmidt dev_dbg(master->dev, "read id %d addr 0x%08x err: %d\n",
6156a794a27SBenjamin Herrenschmidt id, addr, rc);
6166a794a27SBenjamin Herrenschmidt mutex_unlock(&master->lock);
6176a794a27SBenjamin Herrenschmidt
6186a794a27SBenjamin Herrenschmidt return rc;
6196a794a27SBenjamin Herrenschmidt }
6206a794a27SBenjamin Herrenschmidt
fsi_master_acf_write(struct fsi_master * _master,int link,uint8_t id,uint32_t addr,const void * val,size_t size)6216a794a27SBenjamin Herrenschmidt static int fsi_master_acf_write(struct fsi_master *_master, int link,
6226a794a27SBenjamin Herrenschmidt uint8_t id, uint32_t addr, const void *val,
6236a794a27SBenjamin Herrenschmidt size_t size)
6246a794a27SBenjamin Herrenschmidt {
6256a794a27SBenjamin Herrenschmidt struct fsi_master_acf *master = to_fsi_master_acf(_master);
6266a794a27SBenjamin Herrenschmidt struct fsi_msg cmd;
6276a794a27SBenjamin Herrenschmidt int rc;
6286a794a27SBenjamin Herrenschmidt
6296a794a27SBenjamin Herrenschmidt if (link != 0)
6306a794a27SBenjamin Herrenschmidt return -ENODEV;
6316a794a27SBenjamin Herrenschmidt
6326a794a27SBenjamin Herrenschmidt mutex_lock(&master->lock);
6336a794a27SBenjamin Herrenschmidt build_ar_command(master, &cmd, id, addr, size, val);
634d0cff240SBenjamin Herrenschmidt dev_dbg(master->dev, "write id %d addr %x size %zd raw_data: %08x\n",
6356a794a27SBenjamin Herrenschmidt id, addr, size, *(uint32_t *)val);
6366a794a27SBenjamin Herrenschmidt rc = fsi_master_acf_xfer(master, id, &cmd, 0, NULL);
6376a794a27SBenjamin Herrenschmidt last_address_update(master, id, rc == 0, addr);
6386a794a27SBenjamin Herrenschmidt if (rc)
6396a794a27SBenjamin Herrenschmidt dev_dbg(master->dev, "write id %d addr 0x%08x err: %d\n",
6406a794a27SBenjamin Herrenschmidt id, addr, rc);
6416a794a27SBenjamin Herrenschmidt mutex_unlock(&master->lock);
6426a794a27SBenjamin Herrenschmidt
6436a794a27SBenjamin Herrenschmidt return rc;
6446a794a27SBenjamin Herrenschmidt }
6456a794a27SBenjamin Herrenschmidt
fsi_master_acf_term(struct fsi_master * _master,int link,uint8_t id)6466a794a27SBenjamin Herrenschmidt static int fsi_master_acf_term(struct fsi_master *_master,
6476a794a27SBenjamin Herrenschmidt int link, uint8_t id)
6486a794a27SBenjamin Herrenschmidt {
6496a794a27SBenjamin Herrenschmidt struct fsi_master_acf *master = to_fsi_master_acf(_master);
6506a794a27SBenjamin Herrenschmidt struct fsi_msg cmd;
6516a794a27SBenjamin Herrenschmidt int rc;
6526a794a27SBenjamin Herrenschmidt
6536a794a27SBenjamin Herrenschmidt if (link != 0)
6546a794a27SBenjamin Herrenschmidt return -ENODEV;
6556a794a27SBenjamin Herrenschmidt
6566a794a27SBenjamin Herrenschmidt mutex_lock(&master->lock);
6576a794a27SBenjamin Herrenschmidt build_term_command(&cmd, id);
6586a794a27SBenjamin Herrenschmidt dev_dbg(master->dev, "term id %d\n", id);
6596a794a27SBenjamin Herrenschmidt rc = fsi_master_acf_xfer(master, id, &cmd, 0, NULL);
6606a794a27SBenjamin Herrenschmidt last_address_update(master, id, false, 0);
6616a794a27SBenjamin Herrenschmidt mutex_unlock(&master->lock);
6626a794a27SBenjamin Herrenschmidt
6636a794a27SBenjamin Herrenschmidt return rc;
6646a794a27SBenjamin Herrenschmidt }
6656a794a27SBenjamin Herrenschmidt
fsi_master_acf_break(struct fsi_master * _master,int link)6666a794a27SBenjamin Herrenschmidt static int fsi_master_acf_break(struct fsi_master *_master, int link)
6676a794a27SBenjamin Herrenschmidt {
6686a794a27SBenjamin Herrenschmidt struct fsi_master_acf *master = to_fsi_master_acf(_master);
6696a794a27SBenjamin Herrenschmidt int rc;
6706a794a27SBenjamin Herrenschmidt
6716a794a27SBenjamin Herrenschmidt if (link != 0)
6726a794a27SBenjamin Herrenschmidt return -ENODEV;
6736a794a27SBenjamin Herrenschmidt
6746a794a27SBenjamin Herrenschmidt mutex_lock(&master->lock);
6756a794a27SBenjamin Herrenschmidt if (master->external_mode) {
6766a794a27SBenjamin Herrenschmidt mutex_unlock(&master->lock);
6776a794a27SBenjamin Herrenschmidt return -EBUSY;
6786a794a27SBenjamin Herrenschmidt }
6796a794a27SBenjamin Herrenschmidt dev_dbg(master->dev, "sending BREAK\n");
6806a794a27SBenjamin Herrenschmidt rc = do_copro_command(master, CMD_BREAK);
6816a794a27SBenjamin Herrenschmidt last_address_update(master, 0, false, 0);
6826a794a27SBenjamin Herrenschmidt mutex_unlock(&master->lock);
6836a794a27SBenjamin Herrenschmidt
6846a794a27SBenjamin Herrenschmidt /* Wait for logic reset to take effect */
6856a794a27SBenjamin Herrenschmidt udelay(200);
6866a794a27SBenjamin Herrenschmidt
6876a794a27SBenjamin Herrenschmidt return rc;
6886a794a27SBenjamin Herrenschmidt }
6896a794a27SBenjamin Herrenschmidt
reset_cf(struct fsi_master_acf * master)6906a794a27SBenjamin Herrenschmidt static void reset_cf(struct fsi_master_acf *master)
6916a794a27SBenjamin Herrenschmidt {
6926a794a27SBenjamin Herrenschmidt regmap_write(master->scu, SCU_COPRO_CTRL, SCU_COPRO_RESET);
6936a794a27SBenjamin Herrenschmidt usleep_range(20,20);
6946a794a27SBenjamin Herrenschmidt regmap_write(master->scu, SCU_COPRO_CTRL, 0);
6956a794a27SBenjamin Herrenschmidt usleep_range(20,20);
6966a794a27SBenjamin Herrenschmidt }
6976a794a27SBenjamin Herrenschmidt
start_cf(struct fsi_master_acf * master)6986a794a27SBenjamin Herrenschmidt static void start_cf(struct fsi_master_acf *master)
6996a794a27SBenjamin Herrenschmidt {
7006a794a27SBenjamin Herrenschmidt regmap_write(master->scu, SCU_COPRO_CTRL, SCU_COPRO_CLK_EN);
7016a794a27SBenjamin Herrenschmidt }
7026a794a27SBenjamin Herrenschmidt
setup_ast2500_cf_maps(struct fsi_master_acf * master)7036a794a27SBenjamin Herrenschmidt static void setup_ast2500_cf_maps(struct fsi_master_acf *master)
7046a794a27SBenjamin Herrenschmidt {
7056a794a27SBenjamin Herrenschmidt /*
7066a794a27SBenjamin Herrenschmidt * Note about byteswap setting: the bus is wired backwards,
7076a794a27SBenjamin Herrenschmidt * so setting the byteswap bit actually makes the ColdFire
7086a794a27SBenjamin Herrenschmidt * work "normally" for a BE processor, ie, put the MSB in
7096a794a27SBenjamin Herrenschmidt * the lowest address byte.
7106a794a27SBenjamin Herrenschmidt *
7116a794a27SBenjamin Herrenschmidt * We thus need to set the bit for our main memory which
7126a794a27SBenjamin Herrenschmidt * contains our program code. We create two mappings for
7136a794a27SBenjamin Herrenschmidt * the register, one with each setting.
7146a794a27SBenjamin Herrenschmidt *
7156a794a27SBenjamin Herrenschmidt * Segments 2 and 3 has a "swapped" mapping (BE)
7166a794a27SBenjamin Herrenschmidt * and 6 and 7 have a non-swapped mapping (LE) which allows
7176a794a27SBenjamin Herrenschmidt * us to avoid byteswapping register accesses since the
7186a794a27SBenjamin Herrenschmidt * registers are all LE.
7196a794a27SBenjamin Herrenschmidt */
7206a794a27SBenjamin Herrenschmidt
7216a794a27SBenjamin Herrenschmidt /* Setup segment 0 to our memory region */
7226a794a27SBenjamin Herrenschmidt regmap_write(master->scu, SCU_2500_COPRO_SEG0, master->cf_mem_addr |
7236a794a27SBenjamin Herrenschmidt SCU_2500_COPRO_SEG_SWAP);
7246a794a27SBenjamin Herrenschmidt
7256a794a27SBenjamin Herrenschmidt /* Segments 2 and 3 to sysregs with byteswap (for SRAM) */
7266a794a27SBenjamin Herrenschmidt regmap_write(master->scu, SCU_2500_COPRO_SEG2, SYSREG_BASE |
7276a794a27SBenjamin Herrenschmidt SCU_2500_COPRO_SEG_SWAP);
7286a794a27SBenjamin Herrenschmidt regmap_write(master->scu, SCU_2500_COPRO_SEG3, SYSREG_BASE | 0x100000 |
7296a794a27SBenjamin Herrenschmidt SCU_2500_COPRO_SEG_SWAP);
7306a794a27SBenjamin Herrenschmidt
7316a794a27SBenjamin Herrenschmidt /* And segment 6 and 7 to sysregs no byteswap */
7326a794a27SBenjamin Herrenschmidt regmap_write(master->scu, SCU_2500_COPRO_SEG6, SYSREG_BASE);
7336a794a27SBenjamin Herrenschmidt regmap_write(master->scu, SCU_2500_COPRO_SEG7, SYSREG_BASE | 0x100000);
7346a794a27SBenjamin Herrenschmidt
7356a794a27SBenjamin Herrenschmidt /* Memory cachable, regs and SRAM not cachable */
7366a794a27SBenjamin Herrenschmidt regmap_write(master->scu, SCU_2500_COPRO_CACHE_CTL,
7376a794a27SBenjamin Herrenschmidt SCU_2500_COPRO_SEG0_CACHE_EN | SCU_2500_COPRO_CACHE_EN);
7386a794a27SBenjamin Herrenschmidt }
7396a794a27SBenjamin Herrenschmidt
setup_ast2400_cf_maps(struct fsi_master_acf * master)7406a794a27SBenjamin Herrenschmidt static void setup_ast2400_cf_maps(struct fsi_master_acf *master)
7416a794a27SBenjamin Herrenschmidt {
7426a794a27SBenjamin Herrenschmidt /* Setup segment 0 to our memory region */
7436a794a27SBenjamin Herrenschmidt regmap_write(master->scu, SCU_2400_COPRO_SEG0, master->cf_mem_addr |
7446a794a27SBenjamin Herrenschmidt SCU_2400_COPRO_SEG_SWAP);
7456a794a27SBenjamin Herrenschmidt
7466a794a27SBenjamin Herrenschmidt /* Segments 2 to sysregs with byteswap (for SRAM) */
7476a794a27SBenjamin Herrenschmidt regmap_write(master->scu, SCU_2400_COPRO_SEG2, SYSREG_BASE |
7486a794a27SBenjamin Herrenschmidt SCU_2400_COPRO_SEG_SWAP);
7496a794a27SBenjamin Herrenschmidt
7506a794a27SBenjamin Herrenschmidt /* And segment 6 to sysregs no byteswap */
7516a794a27SBenjamin Herrenschmidt regmap_write(master->scu, SCU_2400_COPRO_SEG6, SYSREG_BASE);
7526a794a27SBenjamin Herrenschmidt
7536a794a27SBenjamin Herrenschmidt /* Memory cachable, regs and SRAM not cachable */
7546a794a27SBenjamin Herrenschmidt regmap_write(master->scu, SCU_2400_COPRO_CACHE_CTL,
7556a794a27SBenjamin Herrenschmidt SCU_2400_COPRO_SEG0_CACHE_EN | SCU_2400_COPRO_CACHE_EN);
7566a794a27SBenjamin Herrenschmidt }
7576a794a27SBenjamin Herrenschmidt
setup_common_fw_config(struct fsi_master_acf * master,void __iomem * base)7586a794a27SBenjamin Herrenschmidt static void setup_common_fw_config(struct fsi_master_acf *master,
7596a794a27SBenjamin Herrenschmidt void __iomem *base)
7606a794a27SBenjamin Herrenschmidt {
7616a794a27SBenjamin Herrenschmidt iowrite16be(master->gpio_clk_vreg, base + HDR_CLOCK_GPIO_VADDR);
7626a794a27SBenjamin Herrenschmidt iowrite16be(master->gpio_clk_dreg, base + HDR_CLOCK_GPIO_DADDR);
7636a794a27SBenjamin Herrenschmidt iowrite16be(master->gpio_dat_vreg, base + HDR_DATA_GPIO_VADDR);
7646a794a27SBenjamin Herrenschmidt iowrite16be(master->gpio_dat_dreg, base + HDR_DATA_GPIO_DADDR);
7656a794a27SBenjamin Herrenschmidt iowrite16be(master->gpio_tra_vreg, base + HDR_TRANS_GPIO_VADDR);
7666a794a27SBenjamin Herrenschmidt iowrite16be(master->gpio_tra_dreg, base + HDR_TRANS_GPIO_DADDR);
7676a794a27SBenjamin Herrenschmidt iowrite8(master->gpio_clk_bit, base + HDR_CLOCK_GPIO_BIT);
7686a794a27SBenjamin Herrenschmidt iowrite8(master->gpio_dat_bit, base + HDR_DATA_GPIO_BIT);
7696a794a27SBenjamin Herrenschmidt iowrite8(master->gpio_tra_bit, base + HDR_TRANS_GPIO_BIT);
7706a794a27SBenjamin Herrenschmidt }
7716a794a27SBenjamin Herrenschmidt
setup_ast2500_fw_config(struct fsi_master_acf * master)7726a794a27SBenjamin Herrenschmidt static void setup_ast2500_fw_config(struct fsi_master_acf *master)
7736a794a27SBenjamin Herrenschmidt {
7746a794a27SBenjamin Herrenschmidt void __iomem *base = master->cf_mem + HDR_OFFSET;
7756a794a27SBenjamin Herrenschmidt
7766a794a27SBenjamin Herrenschmidt setup_common_fw_config(master, base);
7776a794a27SBenjamin Herrenschmidt iowrite32be(FW_CONTROL_USE_STOP, base + HDR_FW_CONTROL);
7786a794a27SBenjamin Herrenschmidt }
7796a794a27SBenjamin Herrenschmidt
setup_ast2400_fw_config(struct fsi_master_acf * master)7806a794a27SBenjamin Herrenschmidt static void setup_ast2400_fw_config(struct fsi_master_acf *master)
7816a794a27SBenjamin Herrenschmidt {
7826a794a27SBenjamin Herrenschmidt void __iomem *base = master->cf_mem + HDR_OFFSET;
7836a794a27SBenjamin Herrenschmidt
7846a794a27SBenjamin Herrenschmidt setup_common_fw_config(master, base);
7856a794a27SBenjamin Herrenschmidt iowrite32be(FW_CONTROL_CONT_CLOCK|FW_CONTROL_DUMMY_RD, base + HDR_FW_CONTROL);
7866a794a27SBenjamin Herrenschmidt }
7876a794a27SBenjamin Herrenschmidt
setup_gpios_for_copro(struct fsi_master_acf * master)7886a794a27SBenjamin Herrenschmidt static int setup_gpios_for_copro(struct fsi_master_acf *master)
7896a794a27SBenjamin Herrenschmidt {
7906a794a27SBenjamin Herrenschmidt
7916a794a27SBenjamin Herrenschmidt int rc;
7926a794a27SBenjamin Herrenschmidt
7936a794a27SBenjamin Herrenschmidt /* This aren't under ColdFire control, just set them up appropriately */
7946a794a27SBenjamin Herrenschmidt gpiod_direction_output(master->gpio_mux, 1);
7956a794a27SBenjamin Herrenschmidt gpiod_direction_output(master->gpio_enable, 1);
7966a794a27SBenjamin Herrenschmidt
7976a794a27SBenjamin Herrenschmidt /* Those are under ColdFire control, let it configure them */
7986a794a27SBenjamin Herrenschmidt rc = aspeed_gpio_copro_grab_gpio(master->gpio_clk, &master->gpio_clk_vreg,
7996a794a27SBenjamin Herrenschmidt &master->gpio_clk_dreg, &master->gpio_clk_bit);
8006a794a27SBenjamin Herrenschmidt if (rc) {
8016a794a27SBenjamin Herrenschmidt dev_err(master->dev, "failed to assign clock gpio to coprocessor\n");
8026a794a27SBenjamin Herrenschmidt return rc;
8036a794a27SBenjamin Herrenschmidt }
8046a794a27SBenjamin Herrenschmidt rc = aspeed_gpio_copro_grab_gpio(master->gpio_data, &master->gpio_dat_vreg,
8056a794a27SBenjamin Herrenschmidt &master->gpio_dat_dreg, &master->gpio_dat_bit);
8066a794a27SBenjamin Herrenschmidt if (rc) {
8076a794a27SBenjamin Herrenschmidt dev_err(master->dev, "failed to assign data gpio to coprocessor\n");
8086a794a27SBenjamin Herrenschmidt aspeed_gpio_copro_release_gpio(master->gpio_clk);
8096a794a27SBenjamin Herrenschmidt return rc;
8106a794a27SBenjamin Herrenschmidt }
8116a794a27SBenjamin Herrenschmidt rc = aspeed_gpio_copro_grab_gpio(master->gpio_trans, &master->gpio_tra_vreg,
8126a794a27SBenjamin Herrenschmidt &master->gpio_tra_dreg, &master->gpio_tra_bit);
8136a794a27SBenjamin Herrenschmidt if (rc) {
8146a794a27SBenjamin Herrenschmidt dev_err(master->dev, "failed to assign trans gpio to coprocessor\n");
8156a794a27SBenjamin Herrenschmidt aspeed_gpio_copro_release_gpio(master->gpio_clk);
8166a794a27SBenjamin Herrenschmidt aspeed_gpio_copro_release_gpio(master->gpio_data);
8176a794a27SBenjamin Herrenschmidt return rc;
8186a794a27SBenjamin Herrenschmidt }
8196a794a27SBenjamin Herrenschmidt return 0;
8206a794a27SBenjamin Herrenschmidt }
8216a794a27SBenjamin Herrenschmidt
release_copro_gpios(struct fsi_master_acf * master)8226a794a27SBenjamin Herrenschmidt static void release_copro_gpios(struct fsi_master_acf *master)
8236a794a27SBenjamin Herrenschmidt {
8246a794a27SBenjamin Herrenschmidt aspeed_gpio_copro_release_gpio(master->gpio_clk);
8256a794a27SBenjamin Herrenschmidt aspeed_gpio_copro_release_gpio(master->gpio_data);
8266a794a27SBenjamin Herrenschmidt aspeed_gpio_copro_release_gpio(master->gpio_trans);
8276a794a27SBenjamin Herrenschmidt }
8286a794a27SBenjamin Herrenschmidt
load_copro_firmware(struct fsi_master_acf * master)8296a794a27SBenjamin Herrenschmidt static int load_copro_firmware(struct fsi_master_acf *master)
8306a794a27SBenjamin Herrenschmidt {
8316a794a27SBenjamin Herrenschmidt const struct firmware *fw;
8326a794a27SBenjamin Herrenschmidt uint16_t sig = 0, wanted_sig;
8336a794a27SBenjamin Herrenschmidt const u8 *data;
8346a794a27SBenjamin Herrenschmidt size_t size = 0;
8356a794a27SBenjamin Herrenschmidt int rc;
8366a794a27SBenjamin Herrenschmidt
8376a794a27SBenjamin Herrenschmidt /* Get the binary */
8386a794a27SBenjamin Herrenschmidt rc = request_firmware(&fw, FW_FILE_NAME, master->dev);
8396a794a27SBenjamin Herrenschmidt if (rc) {
8406a794a27SBenjamin Herrenschmidt dev_err(
8418a193982SColin Ian King master->dev, "Error %d to load firmware '%s' !\n",
8426a794a27SBenjamin Herrenschmidt rc, FW_FILE_NAME);
8436a794a27SBenjamin Herrenschmidt return rc;
8446a794a27SBenjamin Herrenschmidt }
8456a794a27SBenjamin Herrenschmidt
8466a794a27SBenjamin Herrenschmidt /* Which image do we want ? (shared vs. split clock/data GPIOs) */
8476a794a27SBenjamin Herrenschmidt if (master->gpio_clk_vreg == master->gpio_dat_vreg)
8486a794a27SBenjamin Herrenschmidt wanted_sig = SYS_SIG_SHARED;
8496a794a27SBenjamin Herrenschmidt else
8506a794a27SBenjamin Herrenschmidt wanted_sig = SYS_SIG_SPLIT;
8516a794a27SBenjamin Herrenschmidt dev_dbg(master->dev, "Looking for image sig %04x\n", wanted_sig);
8526a794a27SBenjamin Herrenschmidt
8536a794a27SBenjamin Herrenschmidt /* Try to find it */
8546a794a27SBenjamin Herrenschmidt for (data = fw->data; data < (fw->data + fw->size);) {
8556a794a27SBenjamin Herrenschmidt sig = be16_to_cpup((__be16 *)(data + HDR_OFFSET + HDR_SYS_SIG));
8566a794a27SBenjamin Herrenschmidt size = be32_to_cpup((__be32 *)(data + HDR_OFFSET + HDR_FW_SIZE));
8576a794a27SBenjamin Herrenschmidt if (sig == wanted_sig)
8586a794a27SBenjamin Herrenschmidt break;
8596a794a27SBenjamin Herrenschmidt data += size;
8606a794a27SBenjamin Herrenschmidt }
8616a794a27SBenjamin Herrenschmidt if (sig != wanted_sig) {
8626a794a27SBenjamin Herrenschmidt dev_err(master->dev, "Failed to locate image sig %04x in FW blob\n",
8636a794a27SBenjamin Herrenschmidt wanted_sig);
864502defbbSGustavo A. R. Silva rc = -ENODEV;
865502defbbSGustavo A. R. Silva goto release_fw;
8666a794a27SBenjamin Herrenschmidt }
8676a794a27SBenjamin Herrenschmidt if (size > master->cf_mem_size) {
8686a794a27SBenjamin Herrenschmidt dev_err(master->dev, "FW size (%zd) bigger than memory reserve (%zd)\n",
8696a794a27SBenjamin Herrenschmidt fw->size, master->cf_mem_size);
8706a794a27SBenjamin Herrenschmidt rc = -ENOMEM;
8716a794a27SBenjamin Herrenschmidt } else {
8726a794a27SBenjamin Herrenschmidt memcpy_toio(master->cf_mem, data, size);
8736a794a27SBenjamin Herrenschmidt }
8746a794a27SBenjamin Herrenschmidt
875502defbbSGustavo A. R. Silva release_fw:
876502defbbSGustavo A. R. Silva release_firmware(fw);
8776a794a27SBenjamin Herrenschmidt return rc;
8786a794a27SBenjamin Herrenschmidt }
8796a794a27SBenjamin Herrenschmidt
check_firmware_image(struct fsi_master_acf * master)8806a794a27SBenjamin Herrenschmidt static int check_firmware_image(struct fsi_master_acf *master)
8816a794a27SBenjamin Herrenschmidt {
8826a794a27SBenjamin Herrenschmidt uint32_t fw_vers, fw_api, fw_options;
8836a794a27SBenjamin Herrenschmidt
8846a794a27SBenjamin Herrenschmidt fw_vers = ioread16be(master->cf_mem + HDR_OFFSET + HDR_FW_VERS);
8856a794a27SBenjamin Herrenschmidt fw_api = ioread16be(master->cf_mem + HDR_OFFSET + HDR_API_VERS);
8866a794a27SBenjamin Herrenschmidt fw_options = ioread32be(master->cf_mem + HDR_OFFSET + HDR_FW_OPTIONS);
8876a794a27SBenjamin Herrenschmidt master->trace_enabled = !!(fw_options & FW_OPTION_TRACE_EN);
8886a794a27SBenjamin Herrenschmidt
8896a794a27SBenjamin Herrenschmidt /* Check version and signature */
8906a794a27SBenjamin Herrenschmidt dev_info(master->dev, "ColdFire initialized, firmware v%d API v%d.%d (trace %s)\n",
8916a794a27SBenjamin Herrenschmidt fw_vers, fw_api >> 8, fw_api & 0xff,
8926a794a27SBenjamin Herrenschmidt master->trace_enabled ? "enabled" : "disabled");
8936a794a27SBenjamin Herrenschmidt
8946a794a27SBenjamin Herrenschmidt if ((fw_api >> 8) != API_VERSION_MAJ) {
8956a794a27SBenjamin Herrenschmidt dev_err(master->dev, "Unsupported coprocessor API version !\n");
8966a794a27SBenjamin Herrenschmidt return -ENODEV;
8976a794a27SBenjamin Herrenschmidt }
8986a794a27SBenjamin Herrenschmidt
8996a794a27SBenjamin Herrenschmidt return 0;
9006a794a27SBenjamin Herrenschmidt }
9016a794a27SBenjamin Herrenschmidt
copro_enable_sw_irq(struct fsi_master_acf * master)9026a794a27SBenjamin Herrenschmidt static int copro_enable_sw_irq(struct fsi_master_acf *master)
9036a794a27SBenjamin Herrenschmidt {
9046a794a27SBenjamin Herrenschmidt int timeout;
9056a794a27SBenjamin Herrenschmidt uint32_t val;
9066a794a27SBenjamin Herrenschmidt
9076a794a27SBenjamin Herrenschmidt /*
9086a794a27SBenjamin Herrenschmidt * Enable coprocessor interrupt input. I've had problems getting the
9096a794a27SBenjamin Herrenschmidt * value to stick, so try in a loop
9106a794a27SBenjamin Herrenschmidt */
9116a794a27SBenjamin Herrenschmidt for (timeout = 0; timeout < 10; timeout++) {
9126a794a27SBenjamin Herrenschmidt iowrite32(0x2, master->cvic + CVIC_EN_REG);
9136a794a27SBenjamin Herrenschmidt val = ioread32(master->cvic + CVIC_EN_REG);
9146a794a27SBenjamin Herrenschmidt if (val & 2)
9156a794a27SBenjamin Herrenschmidt break;
9166a794a27SBenjamin Herrenschmidt msleep(1);
9176a794a27SBenjamin Herrenschmidt }
9186a794a27SBenjamin Herrenschmidt if (!(val & 2)) {
9196a794a27SBenjamin Herrenschmidt dev_err(master->dev, "Failed to enable coprocessor interrupt !\n");
9206a794a27SBenjamin Herrenschmidt return -ENODEV;
9216a794a27SBenjamin Herrenschmidt }
9226a794a27SBenjamin Herrenschmidt return 0;
9236a794a27SBenjamin Herrenschmidt }
9246a794a27SBenjamin Herrenschmidt
fsi_master_acf_setup(struct fsi_master_acf * master)9256a794a27SBenjamin Herrenschmidt static int fsi_master_acf_setup(struct fsi_master_acf *master)
9266a794a27SBenjamin Herrenschmidt {
9276a794a27SBenjamin Herrenschmidt int timeout, rc;
9286a794a27SBenjamin Herrenschmidt uint32_t val;
9296a794a27SBenjamin Herrenschmidt
9306a794a27SBenjamin Herrenschmidt /* Make sure the ColdFire is stopped */
9316a794a27SBenjamin Herrenschmidt reset_cf(master);
9326a794a27SBenjamin Herrenschmidt
9336a794a27SBenjamin Herrenschmidt /*
9346a794a27SBenjamin Herrenschmidt * Clear SRAM. This needs to happen before we setup the GPIOs
9356a794a27SBenjamin Herrenschmidt * as we might start trying to arbitrate as soon as that happens.
9366a794a27SBenjamin Herrenschmidt */
9376a794a27SBenjamin Herrenschmidt memset_io(master->sram, 0, SRAM_SIZE);
9386a794a27SBenjamin Herrenschmidt
9396a794a27SBenjamin Herrenschmidt /* Configure GPIOs */
9406a794a27SBenjamin Herrenschmidt rc = setup_gpios_for_copro(master);
9416a794a27SBenjamin Herrenschmidt if (rc)
9426a794a27SBenjamin Herrenschmidt return rc;
9436a794a27SBenjamin Herrenschmidt
9446a794a27SBenjamin Herrenschmidt /* Load the firmware into the reserved memory */
9456a794a27SBenjamin Herrenschmidt rc = load_copro_firmware(master);
9466a794a27SBenjamin Herrenschmidt if (rc)
9476a794a27SBenjamin Herrenschmidt return rc;
9486a794a27SBenjamin Herrenschmidt
9496a794a27SBenjamin Herrenschmidt /* Read signature and check versions */
9506a794a27SBenjamin Herrenschmidt rc = check_firmware_image(master);
9516a794a27SBenjamin Herrenschmidt if (rc)
9526a794a27SBenjamin Herrenschmidt return rc;
9536a794a27SBenjamin Herrenschmidt
9546a794a27SBenjamin Herrenschmidt /* Setup coldfire memory map */
9556a794a27SBenjamin Herrenschmidt if (master->is_ast2500) {
9566a794a27SBenjamin Herrenschmidt setup_ast2500_cf_maps(master);
9576a794a27SBenjamin Herrenschmidt setup_ast2500_fw_config(master);
9586a794a27SBenjamin Herrenschmidt } else {
9596a794a27SBenjamin Herrenschmidt setup_ast2400_cf_maps(master);
9606a794a27SBenjamin Herrenschmidt setup_ast2400_fw_config(master);
9616a794a27SBenjamin Herrenschmidt }
9626a794a27SBenjamin Herrenschmidt
9636a794a27SBenjamin Herrenschmidt /* Start the ColdFire */
9646a794a27SBenjamin Herrenschmidt start_cf(master);
9656a794a27SBenjamin Herrenschmidt
9666a794a27SBenjamin Herrenschmidt /* Wait for status register to indicate command completion
9676a794a27SBenjamin Herrenschmidt * which signals the initialization is complete
9686a794a27SBenjamin Herrenschmidt */
9696a794a27SBenjamin Herrenschmidt for (timeout = 0; timeout < 10; timeout++) {
9706a794a27SBenjamin Herrenschmidt val = ioread8(master->sram + CF_STARTED);
9716a794a27SBenjamin Herrenschmidt if (val)
9726a794a27SBenjamin Herrenschmidt break;
9736a794a27SBenjamin Herrenschmidt msleep(1);
9746a794a27SBenjamin Herrenschmidt }
9756a794a27SBenjamin Herrenschmidt if (!val) {
9766a794a27SBenjamin Herrenschmidt dev_err(master->dev, "Coprocessor startup timeout !\n");
9776a794a27SBenjamin Herrenschmidt rc = -ENODEV;
9786a794a27SBenjamin Herrenschmidt goto err;
9796a794a27SBenjamin Herrenschmidt }
9806a794a27SBenjamin Herrenschmidt
9816a794a27SBenjamin Herrenschmidt /* Configure echo & send delay */
9826a794a27SBenjamin Herrenschmidt iowrite8(master->t_send_delay, master->sram + SEND_DLY_REG);
9836a794a27SBenjamin Herrenschmidt iowrite8(master->t_echo_delay, master->sram + ECHO_DLY_REG);
9846a794a27SBenjamin Herrenschmidt
9856a794a27SBenjamin Herrenschmidt /* Enable SW interrupt to copro if any */
9866a794a27SBenjamin Herrenschmidt if (master->cvic) {
9876a794a27SBenjamin Herrenschmidt rc = copro_enable_sw_irq(master);
9886a794a27SBenjamin Herrenschmidt if (rc)
9896a794a27SBenjamin Herrenschmidt goto err;
9906a794a27SBenjamin Herrenschmidt }
9916a794a27SBenjamin Herrenschmidt return 0;
9926a794a27SBenjamin Herrenschmidt err:
9936a794a27SBenjamin Herrenschmidt /* An error occurred, don't leave the coprocessor running */
9946a794a27SBenjamin Herrenschmidt reset_cf(master);
9956a794a27SBenjamin Herrenschmidt
9966a794a27SBenjamin Herrenschmidt /* Release the GPIOs */
9976a794a27SBenjamin Herrenschmidt release_copro_gpios(master);
9986a794a27SBenjamin Herrenschmidt
9996a794a27SBenjamin Herrenschmidt return rc;
10006a794a27SBenjamin Herrenschmidt }
10016a794a27SBenjamin Herrenschmidt
10026a794a27SBenjamin Herrenschmidt
fsi_master_acf_terminate(struct fsi_master_acf * master)10036a794a27SBenjamin Herrenschmidt static void fsi_master_acf_terminate(struct fsi_master_acf *master)
10046a794a27SBenjamin Herrenschmidt {
10056a794a27SBenjamin Herrenschmidt unsigned long flags;
10066a794a27SBenjamin Herrenschmidt
10076a794a27SBenjamin Herrenschmidt /*
10086a794a27SBenjamin Herrenschmidt * A GPIO arbitration requestion could come in while this is
10096a794a27SBenjamin Herrenschmidt * happening. To avoid problems, we disable interrupts so it
10106a794a27SBenjamin Herrenschmidt * cannot preempt us on this CPU
10116a794a27SBenjamin Herrenschmidt */
10126a794a27SBenjamin Herrenschmidt
10136a794a27SBenjamin Herrenschmidt local_irq_save(flags);
10146a794a27SBenjamin Herrenschmidt
10156a794a27SBenjamin Herrenschmidt /* Stop the coprocessor */
10166a794a27SBenjamin Herrenschmidt reset_cf(master);
10176a794a27SBenjamin Herrenschmidt
10186a794a27SBenjamin Herrenschmidt /* We mark the copro not-started */
10196a794a27SBenjamin Herrenschmidt iowrite32(0, master->sram + CF_STARTED);
10206a794a27SBenjamin Herrenschmidt
10216a794a27SBenjamin Herrenschmidt /* We mark the ARB register as having given up arbitration to
10226a794a27SBenjamin Herrenschmidt * deal with a potential race with the arbitration request
10236a794a27SBenjamin Herrenschmidt */
10246a794a27SBenjamin Herrenschmidt iowrite8(ARB_ARM_ACK, master->sram + ARB_REG);
10256a794a27SBenjamin Herrenschmidt
10266a794a27SBenjamin Herrenschmidt local_irq_restore(flags);
10276a794a27SBenjamin Herrenschmidt
10286a794a27SBenjamin Herrenschmidt /* Return the GPIOs to the ARM */
10296a794a27SBenjamin Herrenschmidt release_copro_gpios(master);
10306a794a27SBenjamin Herrenschmidt }
10316a794a27SBenjamin Herrenschmidt
fsi_master_acf_setup_external(struct fsi_master_acf * master)10326a794a27SBenjamin Herrenschmidt static void fsi_master_acf_setup_external(struct fsi_master_acf *master)
10336a794a27SBenjamin Herrenschmidt {
10346a794a27SBenjamin Herrenschmidt /* Setup GPIOs for external FSI master (FSP box) */
10356a794a27SBenjamin Herrenschmidt gpiod_direction_output(master->gpio_mux, 0);
10366a794a27SBenjamin Herrenschmidt gpiod_direction_output(master->gpio_trans, 0);
10376a794a27SBenjamin Herrenschmidt gpiod_direction_output(master->gpio_enable, 1);
10386a794a27SBenjamin Herrenschmidt gpiod_direction_input(master->gpio_clk);
10396a794a27SBenjamin Herrenschmidt gpiod_direction_input(master->gpio_data);
10406a794a27SBenjamin Herrenschmidt }
10416a794a27SBenjamin Herrenschmidt
fsi_master_acf_link_enable(struct fsi_master * _master,int link,bool enable)104204635a30SEddie James static int fsi_master_acf_link_enable(struct fsi_master *_master, int link,
104304635a30SEddie James bool enable)
10446a794a27SBenjamin Herrenschmidt {
10456a794a27SBenjamin Herrenschmidt struct fsi_master_acf *master = to_fsi_master_acf(_master);
10466a794a27SBenjamin Herrenschmidt int rc = -EBUSY;
10476a794a27SBenjamin Herrenschmidt
10486a794a27SBenjamin Herrenschmidt if (link != 0)
10496a794a27SBenjamin Herrenschmidt return -ENODEV;
10506a794a27SBenjamin Herrenschmidt
10516a794a27SBenjamin Herrenschmidt mutex_lock(&master->lock);
10526a794a27SBenjamin Herrenschmidt if (!master->external_mode) {
105304635a30SEddie James gpiod_set_value(master->gpio_enable, enable ? 1 : 0);
10546a794a27SBenjamin Herrenschmidt rc = 0;
10556a794a27SBenjamin Herrenschmidt }
10566a794a27SBenjamin Herrenschmidt mutex_unlock(&master->lock);
10576a794a27SBenjamin Herrenschmidt
10586a794a27SBenjamin Herrenschmidt return rc;
10596a794a27SBenjamin Herrenschmidt }
10606a794a27SBenjamin Herrenschmidt
fsi_master_acf_link_config(struct fsi_master * _master,int link,u8 t_send_delay,u8 t_echo_delay)10616a794a27SBenjamin Herrenschmidt static int fsi_master_acf_link_config(struct fsi_master *_master, int link,
10626a794a27SBenjamin Herrenschmidt u8 t_send_delay, u8 t_echo_delay)
10636a794a27SBenjamin Herrenschmidt {
10646a794a27SBenjamin Herrenschmidt struct fsi_master_acf *master = to_fsi_master_acf(_master);
10656a794a27SBenjamin Herrenschmidt
10666a794a27SBenjamin Herrenschmidt if (link != 0)
10676a794a27SBenjamin Herrenschmidt return -ENODEV;
10686a794a27SBenjamin Herrenschmidt
10696a794a27SBenjamin Herrenschmidt mutex_lock(&master->lock);
10706a794a27SBenjamin Herrenschmidt master->t_send_delay = t_send_delay;
10716a794a27SBenjamin Herrenschmidt master->t_echo_delay = t_echo_delay;
10726a794a27SBenjamin Herrenschmidt dev_dbg(master->dev, "Changing delays: send=%d echo=%d\n",
10736a794a27SBenjamin Herrenschmidt t_send_delay, t_echo_delay);
10746a794a27SBenjamin Herrenschmidt iowrite8(master->t_send_delay, master->sram + SEND_DLY_REG);
10756a794a27SBenjamin Herrenschmidt iowrite8(master->t_echo_delay, master->sram + ECHO_DLY_REG);
10766a794a27SBenjamin Herrenschmidt mutex_unlock(&master->lock);
10776a794a27SBenjamin Herrenschmidt
10786a794a27SBenjamin Herrenschmidt return 0;
10796a794a27SBenjamin Herrenschmidt }
10806a794a27SBenjamin Herrenschmidt
external_mode_show(struct device * dev,struct device_attribute * attr,char * buf)10816a794a27SBenjamin Herrenschmidt static ssize_t external_mode_show(struct device *dev,
10826a794a27SBenjamin Herrenschmidt struct device_attribute *attr, char *buf)
10836a794a27SBenjamin Herrenschmidt {
10846a794a27SBenjamin Herrenschmidt struct fsi_master_acf *master = dev_get_drvdata(dev);
10856a794a27SBenjamin Herrenschmidt
10866a794a27SBenjamin Herrenschmidt return snprintf(buf, PAGE_SIZE - 1, "%u\n",
10876a794a27SBenjamin Herrenschmidt master->external_mode ? 1 : 0);
10886a794a27SBenjamin Herrenschmidt }
10896a794a27SBenjamin Herrenschmidt
external_mode_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)10906a794a27SBenjamin Herrenschmidt static ssize_t external_mode_store(struct device *dev,
10916a794a27SBenjamin Herrenschmidt struct device_attribute *attr, const char *buf, size_t count)
10926a794a27SBenjamin Herrenschmidt {
10936a794a27SBenjamin Herrenschmidt struct fsi_master_acf *master = dev_get_drvdata(dev);
10946a794a27SBenjamin Herrenschmidt unsigned long val;
10956a794a27SBenjamin Herrenschmidt bool external_mode;
10966a794a27SBenjamin Herrenschmidt int err;
10976a794a27SBenjamin Herrenschmidt
10986a794a27SBenjamin Herrenschmidt err = kstrtoul(buf, 0, &val);
10996a794a27SBenjamin Herrenschmidt if (err)
11006a794a27SBenjamin Herrenschmidt return err;
11016a794a27SBenjamin Herrenschmidt
11026a794a27SBenjamin Herrenschmidt external_mode = !!val;
11036a794a27SBenjamin Herrenschmidt
11046a794a27SBenjamin Herrenschmidt mutex_lock(&master->lock);
11056a794a27SBenjamin Herrenschmidt
11066a794a27SBenjamin Herrenschmidt if (external_mode == master->external_mode) {
11076a794a27SBenjamin Herrenschmidt mutex_unlock(&master->lock);
11086a794a27SBenjamin Herrenschmidt return count;
11096a794a27SBenjamin Herrenschmidt }
11106a794a27SBenjamin Herrenschmidt
11116a794a27SBenjamin Herrenschmidt master->external_mode = external_mode;
11126a794a27SBenjamin Herrenschmidt if (master->external_mode) {
11136a794a27SBenjamin Herrenschmidt fsi_master_acf_terminate(master);
11146a794a27SBenjamin Herrenschmidt fsi_master_acf_setup_external(master);
11156a794a27SBenjamin Herrenschmidt } else
11166a794a27SBenjamin Herrenschmidt fsi_master_acf_setup(master);
11176a794a27SBenjamin Herrenschmidt
11186a794a27SBenjamin Herrenschmidt mutex_unlock(&master->lock);
11196a794a27SBenjamin Herrenschmidt
11206a794a27SBenjamin Herrenschmidt fsi_master_rescan(&master->master);
11216a794a27SBenjamin Herrenschmidt
11226a794a27SBenjamin Herrenschmidt return count;
11236a794a27SBenjamin Herrenschmidt }
11246a794a27SBenjamin Herrenschmidt
11256a794a27SBenjamin Herrenschmidt static DEVICE_ATTR(external_mode, 0664,
11266a794a27SBenjamin Herrenschmidt external_mode_show, external_mode_store);
11276a794a27SBenjamin Herrenschmidt
fsi_master_acf_gpio_request(void * data)11286a794a27SBenjamin Herrenschmidt static int fsi_master_acf_gpio_request(void *data)
11296a794a27SBenjamin Herrenschmidt {
11306a794a27SBenjamin Herrenschmidt struct fsi_master_acf *master = data;
11316a794a27SBenjamin Herrenschmidt int timeout;
11326a794a27SBenjamin Herrenschmidt u8 val;
11336a794a27SBenjamin Herrenschmidt
11346a794a27SBenjamin Herrenschmidt /* Note: This doesn't require holding out mutex */
11356a794a27SBenjamin Herrenschmidt
1136*f04d61a3SYu Zhe /* Write request */
11376a794a27SBenjamin Herrenschmidt iowrite8(ARB_ARM_REQ, master->sram + ARB_REG);
11386a794a27SBenjamin Herrenschmidt
11396a794a27SBenjamin Herrenschmidt /*
11406a794a27SBenjamin Herrenschmidt * There is a race (which does happen at boot time) when we get an
11416a794a27SBenjamin Herrenschmidt * arbitration request as we are either about to or just starting
11426a794a27SBenjamin Herrenschmidt * the coprocessor.
11436a794a27SBenjamin Herrenschmidt *
11446a794a27SBenjamin Herrenschmidt * To handle it, we first check if we are running. If not yet we
11456a794a27SBenjamin Herrenschmidt * check whether the copro is started in the SCU.
11466a794a27SBenjamin Herrenschmidt *
11476a794a27SBenjamin Herrenschmidt * If it's not started, we can basically just assume we have arbitration
11486a794a27SBenjamin Herrenschmidt * and return. Otherwise, we wait normally expecting for the arbitration
11496a794a27SBenjamin Herrenschmidt * to eventually complete.
11506a794a27SBenjamin Herrenschmidt */
11516a794a27SBenjamin Herrenschmidt if (ioread32(master->sram + CF_STARTED) == 0) {
11526a794a27SBenjamin Herrenschmidt unsigned int reg = 0;
11536a794a27SBenjamin Herrenschmidt
11546a794a27SBenjamin Herrenschmidt regmap_read(master->scu, SCU_COPRO_CTRL, ®);
11556a794a27SBenjamin Herrenschmidt if (!(reg & SCU_COPRO_CLK_EN))
11566a794a27SBenjamin Herrenschmidt return 0;
11576a794a27SBenjamin Herrenschmidt }
11586a794a27SBenjamin Herrenschmidt
11596a794a27SBenjamin Herrenschmidt /* Ring doorbell if any */
11606a794a27SBenjamin Herrenschmidt if (master->cvic)
11616a794a27SBenjamin Herrenschmidt iowrite32(0x2, master->cvic + CVIC_TRIG_REG);
11626a794a27SBenjamin Herrenschmidt
11636a794a27SBenjamin Herrenschmidt for (timeout = 0; timeout < 10000; timeout++) {
11646a794a27SBenjamin Herrenschmidt val = ioread8(master->sram + ARB_REG);
11656a794a27SBenjamin Herrenschmidt if (val != ARB_ARM_REQ)
11666a794a27SBenjamin Herrenschmidt break;
11676a794a27SBenjamin Herrenschmidt udelay(1);
11686a794a27SBenjamin Herrenschmidt }
11696a794a27SBenjamin Herrenschmidt
11706a794a27SBenjamin Herrenschmidt /* If it failed, override anyway */
11716a794a27SBenjamin Herrenschmidt if (val != ARB_ARM_ACK)
11726a794a27SBenjamin Herrenschmidt dev_warn(master->dev, "GPIO request arbitration timeout\n");
11736a794a27SBenjamin Herrenschmidt
11746a794a27SBenjamin Herrenschmidt return 0;
11756a794a27SBenjamin Herrenschmidt }
11766a794a27SBenjamin Herrenschmidt
fsi_master_acf_gpio_release(void * data)11776a794a27SBenjamin Herrenschmidt static int fsi_master_acf_gpio_release(void *data)
11786a794a27SBenjamin Herrenschmidt {
11796a794a27SBenjamin Herrenschmidt struct fsi_master_acf *master = data;
11806a794a27SBenjamin Herrenschmidt
11816a794a27SBenjamin Herrenschmidt /* Write release */
11826a794a27SBenjamin Herrenschmidt iowrite8(0, master->sram + ARB_REG);
11836a794a27SBenjamin Herrenschmidt
11846a794a27SBenjamin Herrenschmidt /* Ring doorbell if any */
11856a794a27SBenjamin Herrenschmidt if (master->cvic)
11866a794a27SBenjamin Herrenschmidt iowrite32(0x2, master->cvic + CVIC_TRIG_REG);
11876a794a27SBenjamin Herrenschmidt
11886a794a27SBenjamin Herrenschmidt return 0;
11896a794a27SBenjamin Herrenschmidt }
11906a794a27SBenjamin Herrenschmidt
fsi_master_acf_release(struct device * dev)11916a794a27SBenjamin Herrenschmidt static void fsi_master_acf_release(struct device *dev)
11926a794a27SBenjamin Herrenschmidt {
1193d5d8dfb0SEddie James struct fsi_master_acf *master = to_fsi_master_acf(to_fsi_master(dev));
11946a794a27SBenjamin Herrenschmidt
11956a794a27SBenjamin Herrenschmidt /* Cleanup, stop coprocessor */
11966a794a27SBenjamin Herrenschmidt mutex_lock(&master->lock);
11976a794a27SBenjamin Herrenschmidt fsi_master_acf_terminate(master);
11986a794a27SBenjamin Herrenschmidt aspeed_gpio_copro_set_ops(NULL, NULL);
11996a794a27SBenjamin Herrenschmidt mutex_unlock(&master->lock);
12006a794a27SBenjamin Herrenschmidt
12016a794a27SBenjamin Herrenschmidt /* Free resources */
12026a794a27SBenjamin Herrenschmidt gen_pool_free(master->sram_pool, (unsigned long)master->sram, SRAM_SIZE);
12036a794a27SBenjamin Herrenschmidt of_node_put(dev_of_node(master->dev));
12046a794a27SBenjamin Herrenschmidt
12056a794a27SBenjamin Herrenschmidt kfree(master);
12066a794a27SBenjamin Herrenschmidt }
12076a794a27SBenjamin Herrenschmidt
12086a794a27SBenjamin Herrenschmidt static const struct aspeed_gpio_copro_ops fsi_master_acf_gpio_ops = {
12096a794a27SBenjamin Herrenschmidt .request_access = fsi_master_acf_gpio_request,
12106a794a27SBenjamin Herrenschmidt .release_access = fsi_master_acf_gpio_release,
12116a794a27SBenjamin Herrenschmidt };
12126a794a27SBenjamin Herrenschmidt
fsi_master_acf_probe(struct platform_device * pdev)12136a794a27SBenjamin Herrenschmidt static int fsi_master_acf_probe(struct platform_device *pdev)
12146a794a27SBenjamin Herrenschmidt {
12156a794a27SBenjamin Herrenschmidt struct device_node *np, *mnode = dev_of_node(&pdev->dev);
12166a794a27SBenjamin Herrenschmidt struct genpool_data_fixed gpdf;
12176a794a27SBenjamin Herrenschmidt struct fsi_master_acf *master;
12186a794a27SBenjamin Herrenschmidt struct gpio_desc *gpio;
12196a794a27SBenjamin Herrenschmidt struct resource res;
12206a794a27SBenjamin Herrenschmidt uint32_t cf_mem_align;
12216a794a27SBenjamin Herrenschmidt int rc;
12226a794a27SBenjamin Herrenschmidt
12236a794a27SBenjamin Herrenschmidt master = kzalloc(sizeof(*master), GFP_KERNEL);
12246a794a27SBenjamin Herrenschmidt if (!master)
12256a794a27SBenjamin Herrenschmidt return -ENOMEM;
12266a794a27SBenjamin Herrenschmidt
12276a794a27SBenjamin Herrenschmidt master->dev = &pdev->dev;
12286a794a27SBenjamin Herrenschmidt master->master.dev.parent = master->dev;
12296a794a27SBenjamin Herrenschmidt master->last_addr = LAST_ADDR_INVALID;
12306a794a27SBenjamin Herrenschmidt
12316a794a27SBenjamin Herrenschmidt /* AST2400 vs. AST2500 */
12326a794a27SBenjamin Herrenschmidt master->is_ast2500 = of_device_is_compatible(mnode, "aspeed,ast2500-cf-fsi-master");
12336a794a27SBenjamin Herrenschmidt
12346a794a27SBenjamin Herrenschmidt /* Grab the SCU, we'll need to access it to configure the coprocessor */
12356a794a27SBenjamin Herrenschmidt if (master->is_ast2500)
12366a794a27SBenjamin Herrenschmidt master->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2500-scu");
12376a794a27SBenjamin Herrenschmidt else
12386a794a27SBenjamin Herrenschmidt master->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2400-scu");
12396a794a27SBenjamin Herrenschmidt if (IS_ERR(master->scu)) {
12406a794a27SBenjamin Herrenschmidt dev_err(&pdev->dev, "failed to find SCU regmap\n");
12416a794a27SBenjamin Herrenschmidt rc = PTR_ERR(master->scu);
12426a794a27SBenjamin Herrenschmidt goto err_free;
12436a794a27SBenjamin Herrenschmidt }
12446a794a27SBenjamin Herrenschmidt
12456a794a27SBenjamin Herrenschmidt /* Grab all the GPIOs we need */
12466a794a27SBenjamin Herrenschmidt gpio = devm_gpiod_get(&pdev->dev, "clock", 0);
12476a794a27SBenjamin Herrenschmidt if (IS_ERR(gpio)) {
12486a794a27SBenjamin Herrenschmidt dev_err(&pdev->dev, "failed to get clock gpio\n");
12496a794a27SBenjamin Herrenschmidt rc = PTR_ERR(gpio);
12506a794a27SBenjamin Herrenschmidt goto err_free;
12516a794a27SBenjamin Herrenschmidt }
12526a794a27SBenjamin Herrenschmidt master->gpio_clk = gpio;
12536a794a27SBenjamin Herrenschmidt
12546a794a27SBenjamin Herrenschmidt gpio = devm_gpiod_get(&pdev->dev, "data", 0);
12556a794a27SBenjamin Herrenschmidt if (IS_ERR(gpio)) {
12566a794a27SBenjamin Herrenschmidt dev_err(&pdev->dev, "failed to get data gpio\n");
12576a794a27SBenjamin Herrenschmidt rc = PTR_ERR(gpio);
12586a794a27SBenjamin Herrenschmidt goto err_free;
12596a794a27SBenjamin Herrenschmidt }
12606a794a27SBenjamin Herrenschmidt master->gpio_data = gpio;
12616a794a27SBenjamin Herrenschmidt
12626a794a27SBenjamin Herrenschmidt /* Optional GPIOs */
12636a794a27SBenjamin Herrenschmidt gpio = devm_gpiod_get_optional(&pdev->dev, "trans", 0);
12646a794a27SBenjamin Herrenschmidt if (IS_ERR(gpio)) {
12656a794a27SBenjamin Herrenschmidt dev_err(&pdev->dev, "failed to get trans gpio\n");
12666a794a27SBenjamin Herrenschmidt rc = PTR_ERR(gpio);
12676a794a27SBenjamin Herrenschmidt goto err_free;
12686a794a27SBenjamin Herrenschmidt }
12696a794a27SBenjamin Herrenschmidt master->gpio_trans = gpio;
12706a794a27SBenjamin Herrenschmidt
12716a794a27SBenjamin Herrenschmidt gpio = devm_gpiod_get_optional(&pdev->dev, "enable", 0);
12726a794a27SBenjamin Herrenschmidt if (IS_ERR(gpio)) {
12736a794a27SBenjamin Herrenschmidt dev_err(&pdev->dev, "failed to get enable gpio\n");
12746a794a27SBenjamin Herrenschmidt rc = PTR_ERR(gpio);
12756a794a27SBenjamin Herrenschmidt goto err_free;
12766a794a27SBenjamin Herrenschmidt }
12776a794a27SBenjamin Herrenschmidt master->gpio_enable = gpio;
12786a794a27SBenjamin Herrenschmidt
12796a794a27SBenjamin Herrenschmidt gpio = devm_gpiod_get_optional(&pdev->dev, "mux", 0);
12806a794a27SBenjamin Herrenschmidt if (IS_ERR(gpio)) {
12816a794a27SBenjamin Herrenschmidt dev_err(&pdev->dev, "failed to get mux gpio\n");
12826a794a27SBenjamin Herrenschmidt rc = PTR_ERR(gpio);
12836a794a27SBenjamin Herrenschmidt goto err_free;
12846a794a27SBenjamin Herrenschmidt }
12856a794a27SBenjamin Herrenschmidt master->gpio_mux = gpio;
12866a794a27SBenjamin Herrenschmidt
12876a794a27SBenjamin Herrenschmidt /* Grab the reserved memory region (use DMA API instead ?) */
12886a794a27SBenjamin Herrenschmidt np = of_parse_phandle(mnode, "memory-region", 0);
12896a794a27SBenjamin Herrenschmidt if (!np) {
12906a794a27SBenjamin Herrenschmidt dev_err(&pdev->dev, "Didn't find reserved memory\n");
12916a794a27SBenjamin Herrenschmidt rc = -EINVAL;
12926a794a27SBenjamin Herrenschmidt goto err_free;
12936a794a27SBenjamin Herrenschmidt }
12946a794a27SBenjamin Herrenschmidt rc = of_address_to_resource(np, 0, &res);
12956a794a27SBenjamin Herrenschmidt of_node_put(np);
12966a794a27SBenjamin Herrenschmidt if (rc) {
12976a794a27SBenjamin Herrenschmidt dev_err(&pdev->dev, "Couldn't address to resource for reserved memory\n");
12986a794a27SBenjamin Herrenschmidt rc = -ENOMEM;
12996a794a27SBenjamin Herrenschmidt goto err_free;
13006a794a27SBenjamin Herrenschmidt }
13016a794a27SBenjamin Herrenschmidt master->cf_mem_size = resource_size(&res);
13026a794a27SBenjamin Herrenschmidt master->cf_mem_addr = (uint32_t)res.start;
13036a794a27SBenjamin Herrenschmidt cf_mem_align = master->is_ast2500 ? 0x00100000 : 0x00200000;
13046a794a27SBenjamin Herrenschmidt if (master->cf_mem_addr & (cf_mem_align - 1)) {
13056a794a27SBenjamin Herrenschmidt dev_err(&pdev->dev, "Reserved memory has insufficient alignment\n");
13066a794a27SBenjamin Herrenschmidt rc = -ENOMEM;
13076a794a27SBenjamin Herrenschmidt goto err_free;
13086a794a27SBenjamin Herrenschmidt }
13096a794a27SBenjamin Herrenschmidt master->cf_mem = devm_ioremap_resource(&pdev->dev, &res);
13106a794a27SBenjamin Herrenschmidt if (IS_ERR(master->cf_mem)) {
13116a794a27SBenjamin Herrenschmidt rc = PTR_ERR(master->cf_mem);
13126a794a27SBenjamin Herrenschmidt goto err_free;
13136a794a27SBenjamin Herrenschmidt }
13146a794a27SBenjamin Herrenschmidt dev_dbg(&pdev->dev, "DRAM allocation @%x\n", master->cf_mem_addr);
13156a794a27SBenjamin Herrenschmidt
13166a794a27SBenjamin Herrenschmidt /* AST2500 has a SW interrupt to the coprocessor */
13176a794a27SBenjamin Herrenschmidt if (master->is_ast2500) {
13186a794a27SBenjamin Herrenschmidt /* Grab the CVIC (ColdFire interrupts controller) */
13196a794a27SBenjamin Herrenschmidt np = of_parse_phandle(mnode, "aspeed,cvic", 0);
13206a794a27SBenjamin Herrenschmidt if (!np) {
13216a794a27SBenjamin Herrenschmidt dev_err(&pdev->dev, "Didn't find CVIC\n");
13226a794a27SBenjamin Herrenschmidt rc = -EINVAL;
13236a794a27SBenjamin Herrenschmidt goto err_free;
13246a794a27SBenjamin Herrenschmidt }
13256a794a27SBenjamin Herrenschmidt master->cvic = devm_of_iomap(&pdev->dev, np, 0, NULL);
13266a794a27SBenjamin Herrenschmidt if (IS_ERR(master->cvic)) {
1327182d98e0SLv Ruyi of_node_put(np);
13286a794a27SBenjamin Herrenschmidt rc = PTR_ERR(master->cvic);
13296a794a27SBenjamin Herrenschmidt dev_err(&pdev->dev, "Error %d mapping CVIC\n", rc);
13306a794a27SBenjamin Herrenschmidt goto err_free;
13316a794a27SBenjamin Herrenschmidt }
13326a794a27SBenjamin Herrenschmidt rc = of_property_read_u32(np, "copro-sw-interrupts",
13336a794a27SBenjamin Herrenschmidt &master->cvic_sw_irq);
1334182d98e0SLv Ruyi of_node_put(np);
13356a794a27SBenjamin Herrenschmidt if (rc) {
13366a794a27SBenjamin Herrenschmidt dev_err(&pdev->dev, "Can't find coprocessor SW interrupt\n");
13376a794a27SBenjamin Herrenschmidt goto err_free;
13386a794a27SBenjamin Herrenschmidt }
13396a794a27SBenjamin Herrenschmidt }
13406a794a27SBenjamin Herrenschmidt
13416a794a27SBenjamin Herrenschmidt /* Grab the SRAM */
13426a794a27SBenjamin Herrenschmidt master->sram_pool = of_gen_pool_get(dev_of_node(&pdev->dev), "aspeed,sram", 0);
13436a794a27SBenjamin Herrenschmidt if (!master->sram_pool) {
13446a794a27SBenjamin Herrenschmidt rc = -ENODEV;
13456a794a27SBenjamin Herrenschmidt dev_err(&pdev->dev, "Can't find sram pool\n");
13466a794a27SBenjamin Herrenschmidt goto err_free;
13476a794a27SBenjamin Herrenschmidt }
13486a794a27SBenjamin Herrenschmidt
13496a794a27SBenjamin Herrenschmidt /* Current microcode only deals with fixed location in SRAM */
13506a794a27SBenjamin Herrenschmidt gpdf.offset = 0;
13516a794a27SBenjamin Herrenschmidt master->sram = (void __iomem *)gen_pool_alloc_algo(master->sram_pool, SRAM_SIZE,
13526a794a27SBenjamin Herrenschmidt gen_pool_fixed_alloc, &gpdf);
13536a794a27SBenjamin Herrenschmidt if (!master->sram) {
13546a794a27SBenjamin Herrenschmidt rc = -ENOMEM;
13556a794a27SBenjamin Herrenschmidt dev_err(&pdev->dev, "Failed to allocate sram from pool\n");
13566a794a27SBenjamin Herrenschmidt goto err_free;
13576a794a27SBenjamin Herrenschmidt }
13586a794a27SBenjamin Herrenschmidt dev_dbg(&pdev->dev, "SRAM allocation @%lx\n",
13596a794a27SBenjamin Herrenschmidt (unsigned long)gen_pool_virt_to_phys(master->sram_pool,
13606a794a27SBenjamin Herrenschmidt (unsigned long)master->sram));
13616a794a27SBenjamin Herrenschmidt
13626a794a27SBenjamin Herrenschmidt /*
13636a794a27SBenjamin Herrenschmidt * Hookup with the GPIO driver for arbitration of GPIO banks
13646a794a27SBenjamin Herrenschmidt * ownership.
13656a794a27SBenjamin Herrenschmidt */
13666a794a27SBenjamin Herrenschmidt aspeed_gpio_copro_set_ops(&fsi_master_acf_gpio_ops, master);
13676a794a27SBenjamin Herrenschmidt
13686a794a27SBenjamin Herrenschmidt /* Default FSI command delays */
13696a794a27SBenjamin Herrenschmidt master->t_send_delay = FSI_SEND_DELAY_CLOCKS;
13706a794a27SBenjamin Herrenschmidt master->t_echo_delay = FSI_ECHO_DELAY_CLOCKS;
13716a794a27SBenjamin Herrenschmidt master->master.n_links = 1;
13726a794a27SBenjamin Herrenschmidt if (master->is_ast2500)
13736a794a27SBenjamin Herrenschmidt master->master.flags = FSI_MASTER_FLAG_SWCLOCK;
13746a794a27SBenjamin Herrenschmidt master->master.read = fsi_master_acf_read;
13756a794a27SBenjamin Herrenschmidt master->master.write = fsi_master_acf_write;
13766a794a27SBenjamin Herrenschmidt master->master.term = fsi_master_acf_term;
13776a794a27SBenjamin Herrenschmidt master->master.send_break = fsi_master_acf_break;
13786a794a27SBenjamin Herrenschmidt master->master.link_enable = fsi_master_acf_link_enable;
13796a794a27SBenjamin Herrenschmidt master->master.link_config = fsi_master_acf_link_config;
13806a794a27SBenjamin Herrenschmidt master->master.dev.of_node = of_node_get(dev_of_node(master->dev));
13816a794a27SBenjamin Herrenschmidt master->master.dev.release = fsi_master_acf_release;
13826a794a27SBenjamin Herrenschmidt platform_set_drvdata(pdev, master);
13836a794a27SBenjamin Herrenschmidt mutex_init(&master->lock);
13846a794a27SBenjamin Herrenschmidt
13856a794a27SBenjamin Herrenschmidt mutex_lock(&master->lock);
13866a794a27SBenjamin Herrenschmidt rc = fsi_master_acf_setup(master);
13876a794a27SBenjamin Herrenschmidt mutex_unlock(&master->lock);
13886a794a27SBenjamin Herrenschmidt if (rc)
13896a794a27SBenjamin Herrenschmidt goto release_of_dev;
13906a794a27SBenjamin Herrenschmidt
13916a794a27SBenjamin Herrenschmidt rc = device_create_file(&pdev->dev, &dev_attr_external_mode);
13926a794a27SBenjamin Herrenschmidt if (rc)
13936a794a27SBenjamin Herrenschmidt goto stop_copro;
13946a794a27SBenjamin Herrenschmidt
13956a794a27SBenjamin Herrenschmidt rc = fsi_master_register(&master->master);
13966a794a27SBenjamin Herrenschmidt if (!rc)
13976a794a27SBenjamin Herrenschmidt return 0;
13986a794a27SBenjamin Herrenschmidt
13996a794a27SBenjamin Herrenschmidt device_remove_file(master->dev, &dev_attr_external_mode);
14006a794a27SBenjamin Herrenschmidt put_device(&master->master.dev);
14016a794a27SBenjamin Herrenschmidt return rc;
14026a794a27SBenjamin Herrenschmidt
14036a794a27SBenjamin Herrenschmidt stop_copro:
14046a794a27SBenjamin Herrenschmidt fsi_master_acf_terminate(master);
14056a794a27SBenjamin Herrenschmidt release_of_dev:
14066a794a27SBenjamin Herrenschmidt aspeed_gpio_copro_set_ops(NULL, NULL);
14076a794a27SBenjamin Herrenschmidt gen_pool_free(master->sram_pool, (unsigned long)master->sram, SRAM_SIZE);
14086a794a27SBenjamin Herrenschmidt of_node_put(dev_of_node(master->dev));
14096a794a27SBenjamin Herrenschmidt err_free:
14106a794a27SBenjamin Herrenschmidt kfree(master);
14116a794a27SBenjamin Herrenschmidt return rc;
14126a794a27SBenjamin Herrenschmidt }
14136a794a27SBenjamin Herrenschmidt
14146a794a27SBenjamin Herrenschmidt
fsi_master_acf_remove(struct platform_device * pdev)14156a794a27SBenjamin Herrenschmidt static int fsi_master_acf_remove(struct platform_device *pdev)
14166a794a27SBenjamin Herrenschmidt {
14176a794a27SBenjamin Herrenschmidt struct fsi_master_acf *master = platform_get_drvdata(pdev);
14186a794a27SBenjamin Herrenschmidt
14196a794a27SBenjamin Herrenschmidt device_remove_file(master->dev, &dev_attr_external_mode);
14206a794a27SBenjamin Herrenschmidt
14216a794a27SBenjamin Herrenschmidt fsi_master_unregister(&master->master);
14226a794a27SBenjamin Herrenschmidt
14236a794a27SBenjamin Herrenschmidt return 0;
14246a794a27SBenjamin Herrenschmidt }
14256a794a27SBenjamin Herrenschmidt
14266a794a27SBenjamin Herrenschmidt static const struct of_device_id fsi_master_acf_match[] = {
14276a794a27SBenjamin Herrenschmidt { .compatible = "aspeed,ast2400-cf-fsi-master" },
14286a794a27SBenjamin Herrenschmidt { .compatible = "aspeed,ast2500-cf-fsi-master" },
14296a794a27SBenjamin Herrenschmidt { },
14306a794a27SBenjamin Herrenschmidt };
143119a52178SZou Wei MODULE_DEVICE_TABLE(of, fsi_master_acf_match);
14326a794a27SBenjamin Herrenschmidt
14336a794a27SBenjamin Herrenschmidt static struct platform_driver fsi_master_acf = {
14346a794a27SBenjamin Herrenschmidt .driver = {
14356a794a27SBenjamin Herrenschmidt .name = "fsi-master-acf",
14366a794a27SBenjamin Herrenschmidt .of_match_table = fsi_master_acf_match,
14376a794a27SBenjamin Herrenschmidt },
14386a794a27SBenjamin Herrenschmidt .probe = fsi_master_acf_probe,
14396a794a27SBenjamin Herrenschmidt .remove = fsi_master_acf_remove,
14406a794a27SBenjamin Herrenschmidt };
14416a794a27SBenjamin Herrenschmidt
14426a794a27SBenjamin Herrenschmidt module_platform_driver(fsi_master_acf);
14436a794a27SBenjamin Herrenschmidt MODULE_LICENSE("GPL");
14443a1d7affSJuerg Haefliger MODULE_FIRMWARE(FW_FILE_NAME);
1445