WG600HPとlzma-loaderとPCIeメモ - 大破雑記帳

大破雑記帳

個人用メモな雑記ブログ いろんなことをざっくりと。

WG600HPとlzma-loaderとPCIeメモ

lzma-loaderでPCIeコントローラ部最低限の初期化をしてVIDとDEVID出すやつ

diff --git a/target/linux/ath79/image/lzma-loader/src/ar71xx_regs.h b/target/linux/ath79/image/lzma-loader/src/ar71xx_regs.h
index e7d7683973..e1737f4fb7 100644
--- a/target/linux/ath79/image/lzma-loader/src/ar71xx_regs.h
+++ b/target/linux/ath79/image/lzma-loader/src/ar71xx_regs.h
@@ -197,7 +197,7 @@
 #define AR71XX_ETH1_PLL_SHIFT      19
 
 #define AR724X_PLL_REG_CPU_CONFIG  0x00
-#define AR724X_PLL_REG_PCIE_CONFIG 0x18
+#define AR724X_PLL_REG_PCIE_CONFIG 0x10
 
 #define AR724X_PLL_DIV_SHIFT       0
 #define AR724X_PLL_DIV_MASK        0x3ff
diff --git a/target/linux/ath79/image/lzma-loader/src/board.c b/target/linux/ath79/image/lzma-loader/src/board.c
index afa2d9e4e9..90e91eb1ca 100644
--- a/target/linux/ath79/image/lzma-loader/src/board.c
+++ b/target/linux/ath79/image/lzma-loader/src/board.c
@@ -211,6 +211,143 @@ static inline void ap5030dn_init(void) { }
     defined(CONFIG_BOARD_NEC_WR8750N) || \
     defined(CONFIG_BOARD_NEC_WR9500N)
 
+#include <stdbool.h>
+#include <unistd.h>
+#include <linux/pci_regs.h>
+
+#define PCIBIOS_SUCCESSFUL     0x0
+#define PCIBIOS_BAD_REGISTER_NUMBER    0x87
+
+static int ar724x_pci_write(int where, int size, unsigned int val, bool devcfg)
+{
+   unsigned int reg, _val;
+   int shift;
+
+   reg = KSEG1ADDR(devcfg ? AR724X_PCI_CFG_BASE : AR724X_PCI_CRP_BASE);
+   _val = READREG(reg + (where & ~3));
+
+   switch (size) {
+   case 1:
+       shift = ((where & 3) * 8);
+       _val &= ~(0xff << shift);
+       _val |= ((val & 0xff) << shift);
+       break;
+   case 2:
+       shift = ((where & 2) * 8);
+       _val &= ~(0xffff << shift);
+       _val |= ((val & 0xffff) << shift);
+       break;
+   case 4:
+       _val = val;
+       break;
+   default:
+       return PCIBIOS_BAD_REGISTER_NUMBER;
+   }
+
+   WRITEREG(reg + (where & ~3), _val);
+   /* flush write */
+   READREG(reg + (where & ~3));
+
+   return PCIBIOS_SUCCESSFUL;
+}
+
+#define ar724x_pci_crp_write(w, s, v)  \
+       ar724x_pci_write(w, s, v, false)
+#define ar724x_pci_cfg_write(w, s, v)  \
+       ar724x_pci_write(w, s, v, true)
+
+static int ar724x_pci_read(int where, int size, unsigned int *val)
+{
+   unsigned int reg, _val;
+
+   reg = KSEG1ADDR(AR724X_PCI_CFG_BASE);
+   _val = READREG(reg + (where & ~3));
+
+   switch (size) {
+   case 1:
+       if (where & 1)
+           _val >>= 8;
+       if (where & 2)
+           _val >>= 16;
+       _val &= 0xff;
+       break;
+   case 2:
+       if (where & 2)
+           _val >>= 16;
+       _val &= 0xffff;
+       break;
+   case 4:
+       break;
+   default:
+       return PCIBIOS_BAD_REGISTER_NUMBER;
+   }
+
+   *val = _val;
+
+   return PCIBIOS_SUCCESSFUL;
+}
+
+#define AR724X_PCI_REG_APP         0x0
+#define AR724X_PCI_REG_RESET           0x18
+
+#define AR934X_PLL_PCIE_CONFIG_PLL_PWD     BIT(30)
+#define AR934X_PLL_PCIE_CONFIG_PLL_BYPASS  BIT(16)
+#define AR724X_PCI_APP_LTSSM_ENABLE        BIT(0)
+#define AR724X_PCI_RESET_EP_RESET_L        BIT(2)
+#define AR724X_PCI_RESET_LINK_UP       BIT(0)
+
+#define AR724X_PCI_CMD_INIT            (PCI_COMMAND_MEMORY | \
+                        PCI_COMMAND_MASTER | \
+                        PCI_COMMAND_INVALIDATE | \
+                        PCI_COMMAND_PARITY | \
+                        PCI_COMMAND_SERR | \
+                        PCI_COMMAND_FAST_BACK)
+
+static void nec_aterm_pcie_init(void)
+{
+   unsigned int reg, val;
+   int i = 0, ret;
+
+   reg = KSEG1ADDR(AR71XX_RESET_BASE);
+   val = READREG(reg + AR934X_RESET_REG_RESET_MODULE);
+   val &= ~(AR934X_RESET_PCIE | AR934X_RESET_PCIE_PHY);
+   WRITEREG(reg + AR934X_RESET_REG_RESET_MODULE, val);
+
+   reg = KSEG1ADDR(AR71XX_PLL_BASE);
+   val = READREG(reg + AR724X_PLL_REG_PCIE_CONFIG);
+   val &= ~(AR934X_PLL_PCIE_CONFIG_PLL_PWD |
+        AR934X_PLL_PCIE_CONFIG_PLL_BYPASS);
+   WRITEREG(reg + AR724X_PLL_REG_PCIE_CONFIG, val);
+
+   reg = KSEG1ADDR(AR724X_PCI_CTRL_BASE);
+   val = READREG(reg + AR724X_PCI_REG_RESET);
+   val |= AR724X_PCI_RESET_EP_RESET_L;
+   WRITEREG(reg + AR724X_PCI_REG_RESET, val);
+
+   val = READREG(reg + AR724X_PCI_REG_APP);
+   val |= AR724X_PCI_APP_LTSSM_ENABLE;
+   WRITEREG(reg + AR724X_PCI_REG_APP, val);
+
+   while (i < 0xffffffff &&
+          !(READREG(reg + AR724X_PCI_REG_RESET)
+        & AR724X_PCI_RESET_LINK_UP))
+       i++;
+   if (i >= 0xffffffff) {
+       printf("failed to initialize PCIe\n");
+       return;
+   }
+
+   ar724x_pci_crp_write(PCI_COMMAND, 4, AR724X_PCI_CMD_INIT);
+
+   ret = ar724x_pci_read(PCI_VENDOR_ID, 4, &val);
+   if (ret) {
+       printf("failed to read PCIe IDs\n");
+       return;
+   }
+   printf("PCIe: vendor->%04x, device->%04x\n",
+          val & 0xffff, val >> 16);
+}
+
 #define AR934X_PLL_SWITCH_CLOCK_CONTROL    0x24
 
 static inline void nec_aterm_init(void)
@@ -239,6 +376,13 @@ static inline void nec_aterm_init(void)
    val = READREG(reg + AR934X_RESET_REG_RESET_MODULE);
    val &= ~(AR934X_RESET_ETH_SWITCH | AR934X_RESET_ETH_SWITCH_ANALOG);
    WRITEREG(reg + AR934X_RESET_REG_RESET_MODULE, val);
+
+   /*
+    * initialize PCIe for activation of ath9k chip to
+    * set default state of the LEDs that connected to
+    * the GPIO controller on the ath9k (AR938x) chip
+    */
+   nec_aterm_pcie_init();
 }
 #else
 static inline void nec_aterm_init(void) {}