diff options
author | Chris Blake <chrisrblake93@gmail.com> | 2018-03-10 10:59:18 +0100 |
---|---|---|
committer | Mathias Kresin <dev@kresin.me> | 2018-03-14 19:04:52 +0100 |
commit | 4943afd7818f56053231a5a7ae90e55da44f1f08 (patch) | |
tree | 3f54b0e72647dc6ef0a595e2e377aeb3ae58a9a9 /target/linux/ipq40xx/patches-4.14/712-mr33-essedma.patch | |
parent | 4f4fc993db4cd074fb2b51586dadd10e882604ec (diff) | |
download | upstream-4943afd7818f56053231a5a7ae90e55da44f1f08.tar.gz upstream-4943afd7818f56053231a5a7ae90e55da44f1f08.tar.bz2 upstream-4943afd7818f56053231a5a7ae90e55da44f1f08.zip |
ipq40xx: add Cisco Meraki MR33 Support
This patch adds support for Cisco Meraki MR33
hardware highlights:
SOC: IPQ4029 Quad-Core ARMv7 Processor rev 5 (v7l) Cortex-A7
DRAM: 256 MiB DDR3L-1600 @ 627 MHz Micron MT41K128M16JT-125IT
NAND: 128 MiB SLC NAND Spansion S34ML01G200TFV00 (106 MiB usable)
ETH: Qualcomm Atheros AR8035 Gigabit PHY (1 x LAN/WAN) + PoE
WLAN1: QCA9887 (168c:0050) PCIe 1x1:1 802.11abgn ac Dualband VHT80
WLAN2: Qualcomm Atheros QCA4029 2.4GHz 802.11bgn 2:2x2
WLAN3: Qualcomm Atheros QCA4029 5GHz 802.11a/n/ac 2:2x2 VHT80
LEDS: 1 x Programmable RGB+White Status LED (driven by Ti LP5562 on i2c-1)
1 x Orange LED Fault Indicator (shared with LP5562)
2 x LAN Activity / Speed LEDs (On the RJ45 Port)
BUTTON: one Reset button
MISC: Bluetooth LE Ti cc2650 PG2.3 4x4mm - BL_CONFIG at 0x0001FFD8
AT24C64 8KiB EEPROM
Kensington Lock
Serial:
WARNING: The serial port needs a TTL/RS-232 3V3 level converter!
The Serial setting is 115200-8-N-1. The board has a populated
1x4 0.1" header with half-height/low profile pins.
The pinout is: VCC (little white arrow), RX, TX, GND.
Flashing needs a serial adaptor, as well as patched ubootwrite utility
(needs Little-Endian support). And a modified u-boot (enabled Ethernet).
Meraki's original u-boot source can be found in:
<https://github.com/riptidewave93/meraki-uboot/tree/mr33-20170427>
Add images to do an installation via bootloader:
0. open up the MR33 and connect the serial console.
1. start the 2nd stage bootloader transfer from client pc:
# ubootwrite.py --write=mr33-uboot.bin
(The ubootwrite tool will interrupt the boot-process and hence
it needs to listen for cues. If the connection is bad (due to
the low-profile pins), the tool can fail multiple times and in
weird ways. If you are not sure, just use a terminal program
and see what the device is doing there.
2. power on the MR33 (with ethernet + serial cables attached)
Warning: Make sure you do this in a private LAN that has
no connection to the internet.
- let it upload the u-boot this can take 250-300 seconds -
3. use a tftp client (in binary mode!) on your PC to upload the sysupgrade.bin
(the u-boot is listening on 192.168.1.1)
# tftp 192.168.1.1
binary
put openwrt-ipq40xx-meraki_mr33-squashfs-sysupgrade.bin
4. wait for it to reboot
5. connect to your MR33 via ssh on 192.168.1.1
For more detailed instructions, please take a look at the:
"Flashing Instructions for the MR33" PDF. This can be found
on the wiki: <https://openwrt.org/toh/meraki/mr33>
(A link to the mr33-uboot.bin + the modified ubootwrite is
also there)
Thanks to Jerome C. for sending an MR33 to Chris.
Signed-off-by: Chris Blake <chrisrblake93@gmail.com>
Signed-off-by: Mathias Kresin <dev@kresin.me>
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
Diffstat (limited to 'target/linux/ipq40xx/patches-4.14/712-mr33-essedma.patch')
-rw-r--r-- | target/linux/ipq40xx/patches-4.14/712-mr33-essedma.patch | 340 |
1 files changed, 340 insertions, 0 deletions
diff --git a/target/linux/ipq40xx/patches-4.14/712-mr33-essedma.patch b/target/linux/ipq40xx/patches-4.14/712-mr33-essedma.patch new file mode 100644 index 0000000000..6be30070d6 --- /dev/null +++ b/target/linux/ipq40xx/patches-4.14/712-mr33-essedma.patch @@ -0,0 +1,340 @@ +--- a/drivers/net/ethernet/qualcomm/essedma/edma_axi.c ++++ b/drivers/net/ethernet/qualcomm/essedma/edma_axi.c +@@ -17,6 +17,11 @@ + #include <linux/of.h> + #include <linux/of_net.h> + #include <linux/timer.h> ++#include <linux/of_platform.h> ++#include <linux/of_address.h> ++#include <linux/clk.h> ++#include <linux/string.h> ++#include <linux/reset.h> + #include "edma.h" + #include "ess_edma.h" + +@@ -83,7 +88,103 @@ void edma_read_reg(u16 reg_addr, volatil + *reg_value = readl((void __iomem *)(edma_hw_addr + reg_addr)); + } + +-/* edma_change_tx_coalesce() ++static void ess_write_reg(struct edma_common_info *edma, u16 reg_addr, u32 reg_value) ++{ ++ writel(reg_value, ((void __iomem *) ++ ((unsigned long)edma->ess_hw_addr + reg_addr))); ++} ++ ++static void ess_read_reg(struct edma_common_info *edma, u16 reg_addr, ++ volatile u32 *reg_value) ++{ ++ *reg_value = readl((void __iomem *) ++ ((unsigned long)edma->ess_hw_addr + reg_addr)); ++} ++ ++static int ess_reset(struct edma_common_info *edma) ++{ ++ struct device_node *switch_node = NULL; ++ struct reset_control *ess_rst; ++ u32 regval; ++ ++ switch_node = of_find_node_by_name(NULL, "ess-switch"); ++ if (!switch_node) { ++ pr_err("switch-node not found\n"); ++ return -EINVAL; ++ } ++ ++ ess_rst = of_reset_control_get(switch_node, "ess_rst"); ++ of_node_put(switch_node); ++ ++ if (IS_ERR(ess_rst)) { ++ pr_err("failed to find ess_rst!\n"); ++ return -ENOENT; ++ } ++ ++ reset_control_assert(ess_rst); ++ msleep(10); ++ reset_control_deassert(ess_rst); ++ msleep(100); ++ reset_control_put(ess_rst); ++ ++ /* Enable only port 5 <--> port 0 ++ * bits 0:6 bitmap of ports it can fwd to */ ++#define SET_PORT_BMP(r,v) \ ++ ess_read_reg(edma, r, ®val); \ ++ ess_write_reg(edma, r, ((regval & ~0x3F) | v)); ++ ++ SET_PORT_BMP(ESS_PORT0_LOOKUP_CTRL,0x20); ++ SET_PORT_BMP(ESS_PORT1_LOOKUP_CTRL,0x00); ++ SET_PORT_BMP(ESS_PORT2_LOOKUP_CTRL,0x00); ++ SET_PORT_BMP(ESS_PORT3_LOOKUP_CTRL,0x00); ++ SET_PORT_BMP(ESS_PORT4_LOOKUP_CTRL,0x00); ++ SET_PORT_BMP(ESS_PORT5_LOOKUP_CTRL,0x01); ++ ess_write_reg(edma, ESS_RGMII_CTRL, 0x400); ++ ess_write_reg(edma, ESS_PORT0_STATUS, ESS_PORT_1G_FDX); ++ ess_write_reg(edma, ESS_PORT5_STATUS, ESS_PORT_1G_FDX); ++ ess_write_reg(edma, ESS_PORT0_HEADER_CTRL, 0); ++#undef SET_PORT_BMP ++ ++ /* forward multicast and broadcast frames to CPU */ ++ ess_write_reg(edma, ESS_FWD_CTRL1, ++ (ESS_PORTS_ALL << ESS_FWD_CTRL1_UC_FLOOD_S) | ++ (ESS_PORTS_ALL << ESS_FWD_CTRL1_MC_FLOOD_S) | ++ (ESS_PORTS_ALL << ESS_FWD_CTRL1_BC_FLOOD_S)); ++ ++ return 0; ++} ++ ++void ess_set_port_status_speed(struct edma_common_info *edma, ++ struct phy_device *phydev, uint8_t port_id) ++{ ++ uint16_t reg_off = ESS_PORT0_STATUS + (4 * port_id); ++ uint32_t reg_val = 0; ++ ++ ess_read_reg(edma, reg_off, ®_val); ++ ++ /* reset the speed bits [0:1] */ ++ reg_val &= ~ESS_PORT_STATUS_SPEED_INV; ++ ++ /* set the new speed */ ++ switch(phydev->speed) { ++ case SPEED_1000: reg_val |= ESS_PORT_STATUS_SPEED_1000; break; ++ case SPEED_100: reg_val |= ESS_PORT_STATUS_SPEED_100; break; ++ case SPEED_10: reg_val |= ESS_PORT_STATUS_SPEED_10; break; ++ default: reg_val |= ESS_PORT_STATUS_SPEED_INV; break; ++ } ++ ++ /* check full/half duplex */ ++ if (phydev->duplex) { ++ reg_val |= ESS_PORT_STATUS_DUPLEX_MODE; ++ } else { ++ reg_val &= ~ESS_PORT_STATUS_DUPLEX_MODE; ++ } ++ ++ ess_write_reg(edma, reg_off, reg_val); ++} ++ ++/* ++ * edma_change_tx_coalesce() + * change tx interrupt moderation timer + */ + void edma_change_tx_coalesce(int usecs) +@@ -551,6 +652,31 @@ static struct ctl_table edma_table[] = { + {} + }; + ++static int ess_parse(struct edma_common_info *edma) ++{ ++ struct device_node *switch_node; ++ int ret = -EINVAL; ++ ++ switch_node = of_find_node_by_name(NULL, "ess-switch"); ++ if (!switch_node) { ++ pr_err("cannot find ess-switch node\n"); ++ goto out; ++ } ++ ++ edma->ess_hw_addr = of_io_request_and_map(switch_node, ++ 0, KBUILD_MODNAME); ++ if (!edma->ess_hw_addr) { ++ pr_err("%s ioremap fail.", __func__); ++ goto out; ++ } ++ ++ edma->ess_clk = of_clk_get_by_name(switch_node, "ess_clk"); ++ ret = clk_prepare_enable(edma->ess_clk); ++out: ++ of_node_put(switch_node); ++ return ret; ++} ++ + /* edma_axi_netdev_ops + * Describe the operations supported by registered netdevices + * +@@ -786,6 +912,17 @@ static int edma_axi_probe(struct platfor + miibus = mdio_data->mii_bus; + } + ++ if (of_property_read_bool(np, "qcom,single-phy") && ++ edma_cinfo->num_gmac == 1) { ++ err = ess_parse(edma_cinfo); ++ if (!err) ++ err = ess_reset(edma_cinfo); ++ if (err) ++ goto err_single_phy_init; ++ else ++ edma_cinfo->is_single_phy = true; ++ } ++ + for_each_available_child_of_node(np, pnp) { + const char *mac_addr; + +@@ -1074,11 +1211,15 @@ static int edma_axi_probe(struct platfor + + for (i = 0; i < edma_cinfo->num_gmac; i++) { + if (adapter[i]->poll_required) { ++ int phy_mode = of_get_phy_mode(np); ++ ++ if (phy_mode < 0) ++ phy_mode = PHY_INTERFACE_MODE_SGMII; + adapter[i]->phydev = + phy_connect(edma_netdev[i], + (const char *)adapter[i]->phy_id, + &edma_adjust_link, +- PHY_INTERFACE_MODE_SGMII); ++ phy_mode); + if (IS_ERR(adapter[i]->phydev)) { + dev_dbg(&pdev->dev, "PHY attach FAIL"); + err = -EIO; +@@ -1125,6 +1266,9 @@ err_rmap_alloc_fail: + for (i = 0; i < edma_cinfo->num_gmac; i++) + unregister_netdev(edma_netdev[i]); + err_register: ++err_single_phy_init: ++ iounmap(edma_cinfo->ess_hw_addr); ++ clk_disable_unprepare(edma_cinfo->ess_clk); + err_mdiobus_init_fail: + edma_free_rx_rings(edma_cinfo); + err_rx_rinit: +@@ -1185,6 +1329,8 @@ static int edma_axi_remove(struct platfo + del_timer_sync(&edma_stats_timer); + edma_free_irqs(adapter); + unregister_net_sysctl_table(edma_cinfo->edma_ctl_table_hdr); ++ iounmap(edma_cinfo->ess_hw_addr); ++ clk_disable_unprepare(edma_cinfo->ess_clk); + edma_free_tx_resources(edma_cinfo); + edma_free_rx_resources(edma_cinfo); + edma_free_tx_rings(edma_cinfo); +--- a/drivers/net/ethernet/qualcomm/essedma/edma.c ++++ b/drivers/net/ethernet/qualcomm/essedma/edma.c +@@ -161,8 +161,10 @@ static void edma_configure_rx(struct edm + /* Set Rx FIFO threshold to start to DMA data to host */ + rxq_ctrl_data = EDMA_FIFO_THRESH_128_BYTE; + +- /* Set RX remove vlan bit */ +- rxq_ctrl_data |= EDMA_RXQ_CTRL_RMV_VLAN; ++ if (!edma_cinfo->is_single_phy) { ++ /* Set RX remove vlan bit */ ++ rxq_ctrl_data |= EDMA_RXQ_CTRL_RMV_VLAN; ++ } + + edma_write_reg(EDMA_REG_RXQ_CTRL, rxq_ctrl_data); + } +@@ -1295,6 +1297,10 @@ void edma_adjust_link(struct net_device + if (status == __EDMA_LINKUP && adapter->link_state == __EDMA_LINKDOWN) { + dev_info(&adapter->pdev->dev, "%s: GMAC Link is up with phy_speed=%d\n", netdev->name, phydev->speed); + adapter->link_state = __EDMA_LINKUP; ++ if (adapter->edma_cinfo->is_single_phy) { ++ ess_set_port_status_speed(adapter->edma_cinfo, phydev, ++ ffs(adapter->dp_bitmap) - 1); ++ } + netif_carrier_on(netdev); + if (netif_running(netdev)) + netif_tx_wake_all_queues(netdev); +@@ -1388,10 +1394,12 @@ netdev_tx_t edma_xmit(struct sk_buff *sk + } + + /* Check and mark VLAN tag offload */ +- if (skb_vlan_tag_present(skb)) +- flags_transmit |= EDMA_VLAN_TX_TAG_INSERT_FLAG; +- else if (adapter->default_vlan_tag) +- flags_transmit |= EDMA_VLAN_TX_TAG_INSERT_DEFAULT_FLAG; ++ if (!adapter->edma_cinfo->is_single_phy) { ++ if (unlikely(skb_vlan_tag_present(skb))) ++ flags_transmit |= EDMA_VLAN_TX_TAG_INSERT_FLAG; ++ else if (adapter->default_vlan_tag) ++ flags_transmit |= EDMA_VLAN_TX_TAG_INSERT_DEFAULT_FLAG; ++ } + + /* Check and mark checksum offload */ + if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) +--- a/drivers/net/ethernet/qualcomm/essedma/edma.h ++++ b/drivers/net/ethernet/qualcomm/essedma/edma.h +@@ -31,6 +31,7 @@ + #include <linux/platform_device.h> + #include <linux/of.h> + #include <linux/of_device.h> ++#include <linux/clk.h> + #include <linux/kernel.h> + #include <linux/device.h> + #include <linux/sysctl.h> +@@ -331,6 +332,10 @@ struct edma_common_info { + struct edma_hw hw; /* edma hw specific structure */ + struct edma_per_cpu_queues_info edma_percpu_info[CONFIG_NR_CPUS]; /* per cpu information */ + spinlock_t stats_lock; /* protect edma stats area for updation */ ++ ++ bool is_single_phy; ++ void __iomem *ess_hw_addr; ++ struct clk *ess_clk; + }; + + /* transimit packet descriptor (tpd) ring */ +@@ -443,4 +448,6 @@ void edma_change_tx_coalesce(int usecs); + void edma_change_rx_coalesce(int usecs); + void edma_get_tx_rx_coalesce(u32 *reg_val); + void edma_clear_irq_status(void); ++void ess_set_port_status_speed(struct edma_common_info *edma_cinfo, ++ struct phy_device *phydev, uint8_t port_id); + #endif /* _EDMA_H_ */ +--- a/drivers/net/ethernet/qualcomm/essedma/ess_edma.h ++++ b/drivers/net/ethernet/qualcomm/essedma/ess_edma.h +@@ -329,4 +329,61 @@ struct edma_hw; + #define EDMA_RRD_PRIORITY_MASK 0x7 + #define EDMA_RRD_PORT_TYPE_SHIFT 7 + #define EDMA_RRD_PORT_TYPE_MASK 0x1F ++ ++#define ESS_RGMII_CTRL 0x0004 ++ ++/* Port status registers */ ++#define ESS_PORT0_STATUS 0x007C ++#define ESS_PORT1_STATUS 0x0080 ++#define ESS_PORT2_STATUS 0x0084 ++#define ESS_PORT3_STATUS 0x0088 ++#define ESS_PORT4_STATUS 0x008C ++#define ESS_PORT5_STATUS 0x0090 ++ ++#define ESS_PORT_STATUS_HDX_FLOW_CTL 0x80 ++#define ESS_PORT_STATUS_DUPLEX_MODE 0x40 ++#define ESS_PORT_STATUS_RX_FLOW_EN 0x20 ++#define ESS_PORT_STATUS_TX_FLOW_EN 0x10 ++#define ESS_PORT_STATUS_RX_MAC_EN 0x08 ++#define ESS_PORT_STATUS_TX_MAC_EN 0x04 ++#define ESS_PORT_STATUS_SPEED_INV 0x03 ++#define ESS_PORT_STATUS_SPEED_1000 0x02 ++#define ESS_PORT_STATUS_SPEED_100 0x01 ++#define ESS_PORT_STATUS_SPEED_10 0x00 ++ ++#define ESS_PORT_1G_FDX (ESS_PORT_STATUS_DUPLEX_MODE | ESS_PORT_STATUS_RX_FLOW_EN | \ ++ ESS_PORT_STATUS_TX_FLOW_EN | ESS_PORT_STATUS_RX_MAC_EN | \ ++ ESS_PORT_STATUS_TX_MAC_EN | ESS_PORT_STATUS_SPEED_1000) ++ ++#define PHY_STATUS_REG 0x11 ++#define PHY_STATUS_SPEED 0xC000 ++#define PHY_STATUS_SPEED_SHIFT 14 ++#define PHY_STATUS_DUPLEX 0x2000 ++#define PHY_STATUS_DUPLEX_SHIFT 13 ++#define PHY_STATUS_SPEED_DUPLEX_RESOLVED 0x0800 ++#define PHY_STATUS_CARRIER 0x0400 ++#define PHY_STATUS_CARRIER_SHIFT 10 ++ ++/* Port lookup control registers */ ++#define ESS_PORT0_LOOKUP_CTRL 0x0660 ++#define ESS_PORT1_LOOKUP_CTRL 0x066C ++#define ESS_PORT2_LOOKUP_CTRL 0x0678 ++#define ESS_PORT3_LOOKUP_CTRL 0x0684 ++#define ESS_PORT4_LOOKUP_CTRL 0x0690 ++#define ESS_PORT5_LOOKUP_CTRL 0x069C ++ ++#define ESS_PORT0_HEADER_CTRL 0x009C ++ ++#define ESS_PORTS_ALL 0x3f ++ ++#define ESS_FWD_CTRL1 0x0624 ++#define ESS_FWD_CTRL1_UC_FLOOD BITS(0, 7) ++#define ESS_FWD_CTRL1_UC_FLOOD_S 0 ++#define ESS_FWD_CTRL1_MC_FLOOD BITS(8, 7) ++#define ESS_FWD_CTRL1_MC_FLOOD_S 8 ++#define ESS_FWD_CTRL1_BC_FLOOD BITS(16, 7) ++#define ESS_FWD_CTRL1_BC_FLOOD_S 16 ++#define ESS_FWD_CTRL1_IGMP BITS(24, 7) ++#define ESS_FWD_CTRL1_IGMP_S 24 ++ + #endif /* _ESS_EDMA_H_ */ |