From f861ce8a61cddfd44f873ad9a4c9c14381c9d080 Mon Sep 17 00:00:00 2001 From: coolsnowwolf Date: Fri, 5 Aug 2022 06:38:54 +0000 Subject: [PATCH] rockchip: refresh 5.19 patch --- target/linux/rockchip/Makefile | 2 +- ...dd-support-for-FriendlyARM-NanoPi-N.patch} | 0 ...add-driver-for-Motorcomm-YT85xx+PHYs.patch | 2243 +++++++++++++++ ...ip-add-hardware-random-number-genera.patch | 50 + ...ip-add-devfreq-driver-for-rk3328-dmc.patch | 44 + ...setting-ddr-clock-via-SIP-Version-2-.patch | 210 ++ ...eq-rockchip-dfi-add-more-soc-support.patch | 662 +++++ ...m64-dts-rockchip-rk3328-add-dfi-node.patch | 27 + ...anopi-r2s-add-rk3328-dmc-relate-node.patch | 126 + ...drv-net-phy-add-JLSemi-jl2xxx-driver.patch | 702 +++++ .../0900-arm-boot-add-dts-files.patch | 34 + ...overclock-to-2.2-1.8-GHz-for-NanoPi4.patch | 21 + ...ip-add-more-cpu-operating-points-for.patch | 44 + ...o-rockchip-permit-to-pass-self-tests.patch | 2419 +++++++++++++++++ 14 files changed, 6583 insertions(+), 1 deletion(-) rename target/linux/rockchip/patches-5.19/{111-rockchip-rk3328-add-support-for-FriendlyARM-NanoPi-N.patch => 0055-rockchip-rk3328-add-support-for-FriendlyARM-NanoPi-N.patch} (100%) create mode 100644 target/linux/rockchip/patches-5.19/0056-add-driver-for-Motorcomm-YT85xx+PHYs.patch create mode 100644 target/linux/rockchip/patches-5.19/0057-arm64-dts-rockchip-add-hardware-random-number-genera.patch create mode 100644 target/linux/rockchip/patches-5.19/0058-PM-devfreq-rockchip-add-devfreq-driver-for-rk3328-dmc.patch create mode 100644 target/linux/rockchip/patches-5.19/0059-clk-rockchip-support-setting-ddr-clock-via-SIP-Version-2-.patch create mode 100644 target/linux/rockchip/patches-5.19/0060-PM-devfreq-rockchip-dfi-add-more-soc-support.patch create mode 100644 target/linux/rockchip/patches-5.19/0061-arm64-dts-rockchip-rk3328-add-dfi-node.patch create mode 100644 target/linux/rockchip/patches-5.19/0062-arm64-dts-nanopi-r2s-add-rk3328-dmc-relate-node.patch create mode 100644 target/linux/rockchip/patches-5.19/0063-drv-net-phy-add-JLSemi-jl2xxx-driver.patch create mode 100644 target/linux/rockchip/patches-5.19/0900-arm-boot-add-dts-files.patch create mode 100644 target/linux/rockchip/patches-5.19/0901-rockchip-rk3399-overclock-to-2.2-1.8-GHz-for-NanoPi4.patch create mode 100644 target/linux/rockchip/patches-5.19/0902-arm64-dts-rockchip-add-more-cpu-operating-points-for.patch create mode 100644 target/linux/rockchip/patches-5.19/0903-crypto-rockchip-permit-to-pass-self-tests.patch diff --git a/target/linux/rockchip/Makefile b/target/linux/rockchip/Makefile index e616ba05c..82ac5ef9d 100644 --- a/target/linux/rockchip/Makefile +++ b/target/linux/rockchip/Makefile @@ -8,7 +8,7 @@ FEATURES:=ext4 audio usb usbgadget display gpio fpu pci pcie rootfs-part boot-pa SUBTARGETS:=armv8 KERNEL_PATCHVER=5.15 -KERNEL_TESTING_PATCHVER=5.4 +KERNEL_TESTING_PATCHVER=5.19 define Target/Description Build firmware image for Rockchip SoC devices. diff --git a/target/linux/rockchip/patches-5.19/111-rockchip-rk3328-add-support-for-FriendlyARM-NanoPi-N.patch b/target/linux/rockchip/patches-5.19/0055-rockchip-rk3328-add-support-for-FriendlyARM-NanoPi-N.patch similarity index 100% rename from target/linux/rockchip/patches-5.19/111-rockchip-rk3328-add-support-for-FriendlyARM-NanoPi-N.patch rename to target/linux/rockchip/patches-5.19/0055-rockchip-rk3328-add-support-for-FriendlyARM-NanoPi-N.patch diff --git a/target/linux/rockchip/patches-5.19/0056-add-driver-for-Motorcomm-YT85xx+PHYs.patch b/target/linux/rockchip/patches-5.19/0056-add-driver-for-Motorcomm-YT85xx+PHYs.patch new file mode 100644 index 000000000..26227e020 --- /dev/null +++ b/target/linux/rockchip/patches-5.19/0056-add-driver-for-Motorcomm-YT85xx+PHYs.patch @@ -0,0 +1,2243 @@ +--- a/drivers/net/phy/motorcomm.c ++++ b/drivers/net/phy/motorcomm.c +@@ -1,137 +1,1540 @@ +-// SPDX-License-Identifier: GPL-2.0+ + /* ++ * drivers/net/phy/motorcomm.c ++ * + * Driver for Motorcomm PHYs + * +- * Author: Peter Geis ++ * Author: Leilei Zhao ++ * ++ * Copyright (c) 2019 Motorcomm, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * Support : Motorcomm Phys: ++ * Giga phys: yt8511, yt8521 ++ * 100/10 Phys : yt8512, yt8512b, yt8510 ++ * Automotive 100Mb Phys : yt8010 ++ * Automotive 100/10 hyper range Phys: yt8510 + */ + + #include + #include + #include ++#include ++#include ++#include ++#include ++#ifndef LINUX_VERSION_CODE ++#include ++#else ++#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) ++#endif ++/*for wol, 20210604*/ ++#include ++ ++#include "yt8614-phy.h" ++ ++/**** configuration section begin ***********/ ++ ++/* if system depends on ethernet packet to restore from sleep, please define this macro to 1 ++ * otherwise, define it to 0. ++ */ ++#define SYS_WAKEUP_BASED_ON_ETH_PKT 1 ++ ++/* to enable system WOL of phy, please define this macro to 1 ++ * otherwise, define it to 0. ++ */ ++#define YTPHY_ENABLE_WOL 0 ++ ++/* some GMAC need clock input from PHY, for eg., 125M, please enable this macro ++ * by degault, it is set to 0 ++ * NOTE: this macro will need macro SYS_WAKEUP_BASED_ON_ETH_PKT to set to 1 ++ */ ++#define GMAC_CLOCK_INPUT_NEEDED 1 + +-#define PHY_ID_YT8511 0x0000010a + +-#define YT8511_PAGE_SELECT 0x1e +-#define YT8511_PAGE 0x1f +-#define YT8511_EXT_CLK_GATE 0x0c +-#define YT8511_EXT_DELAY_DRIVE 0x0d +-#define YT8511_EXT_SLEEP_CTRL 0x27 +- +-/* 2b00 25m from pll +- * 2b01 25m from xtl *default* +- * 2b10 62.m from pll +- * 2b11 125m from pll +- */ +-#define YT8511_CLK_125M (BIT(2) | BIT(1)) +-#define YT8511_PLLON_SLP BIT(14) +- +-/* RX Delay enabled = 1.8ns 1000T, 8ns 10/100T */ +-#define YT8511_DELAY_RX BIT(0) +- +-/* TX Gig-E Delay is bits 7:4, default 0x5 +- * TX Fast-E Delay is bits 15:12, default 0xf +- * Delay = 150ps * N - 250ps +- * On = 2000ps, off = 50ps +- */ +-#define YT8511_DELAY_GE_TX_EN (0xf << 4) +-#define YT8511_DELAY_GE_TX_DIS (0x2 << 4) +-#define YT8511_DELAY_FE_TX_EN (0xf << 12) +-#define YT8511_DELAY_FE_TX_DIS (0x2 << 12) ++#define YT8521_PHY_MODE_FIBER 1 //fiber mode only ++#define YT8521_PHY_MODE_UTP 2 //utp mode only ++#define YT8521_PHY_MODE_POLL 3 //fiber and utp, poll mode + +-static int yt8511_read_page(struct phy_device *phydev) ++/* please make choice according to system design ++ * for Fiber only system, please define YT8521_PHY_MODE_CURR 1 ++ * for UTP only system, please define YT8521_PHY_MODE_CURR 2 ++ * for combo system, please define YT8521_PHY_MODE_CURR 3 ++ */ ++#define YT8521_PHY_MODE_CURR 3 ++ ++/**** configuration section end ***********/ ++ ++ ++/* no need to change below */ ++ ++#if (YTPHY_ENABLE_WOL) ++#undef SYS_WAKEUP_BASED_ON_ETH_PKT ++#define SYS_WAKEUP_BASED_ON_ETH_PKT 1 ++#endif ++ ++/* workaround for 8521 fiber 100m mode */ ++static int link_mode_8521 = 0; //0: no link; 1: utp; 32: fiber. traced that 1000m fiber uses 32. ++static int link_mode_8614[4] = {0}; //0: no link; 1: utp; 32: fiber. traced that 1000m fiber uses 32. ++ ++/* for multiple port phy, base phy address */ ++static unsigned int yt_mport_base_phy_addr = 0xff; //0xff: invalid; for 8618 ++static unsigned int yt_mport_base_phy_addr_8614 = 0xff; //0xff: invalid; ++ ++int phy_yt8531_led_fixup(struct mii_bus *bus, int addr); ++int yt8511_config_out_125m(struct mii_bus *bus, int phy_id); ++ ++#if ( LINUX_VERSION_CODE > KERNEL_VERSION(5,0,0) ) ++int genphy_config_init(struct phy_device *phydev) + { +- return __phy_read(phydev, YT8511_PAGE_SELECT); +-}; ++ int ret; ++ ++ printk (KERN_INFO "yzhang..read phyaddr=%d, phyid=%08x\n",phydev->mdio.addr, phydev->phy_id); + +-static int yt8511_write_page(struct phy_device *phydev, int page) ++ if(phydev->phy_id == 0x4f51e91b) ++ { ++ printk (KERN_INFO "yzhang..get YT8511, abt to set 125m clk out, phyaddr=%d, phyid=%08x\n",phydev->mdio.addr, phydev->phy_id); ++ ret = yt8511_config_out_125m(phydev->mdio.bus, phydev->mdio.addr); ++ printk (KERN_INFO "yzhang..8511 set 125m clk out, reg=%#04x\n",phydev->mdio.bus->read(phydev->mdio.bus,phydev->mdio.addr,0x1f)/*double check as delay*/); ++ if (ret<0) ++ printk (KERN_INFO "yzhang..failed to set 125m clk out, ret=%d\n",ret); ++ ++ phy_yt8531_led_fixup(phydev->mdio.bus, phydev->mdio.addr); ++ } ++ return genphy_read_abilities(phydev); ++} ++#endif ++ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++static int ytphy_config_init(struct phy_device *phydev) + { +- return __phy_write(phydev, YT8511_PAGE_SELECT, page); +-}; ++ return 0; ++} ++#endif ++ ++static int ytphy_read_ext(struct phy_device *phydev, u32 regnum) ++{ ++ int ret; ++ int val; ++ ++ ret = phy_write(phydev, REG_DEBUG_ADDR_OFFSET, regnum); ++ if (ret < 0) ++ return ret; ++ ++ val = phy_read(phydev, REG_DEBUG_DATA); ++ ++ return val; ++} ++ ++static int ytphy_write_ext(struct phy_device *phydev, u32 regnum, u16 val) ++{ ++ int ret; ++ ++ ret = phy_write(phydev, REG_DEBUG_ADDR_OFFSET, regnum); ++ if (ret < 0) ++ return ret; ++ ++ ret = phy_write(phydev, REG_DEBUG_DATA, val); ++ ++ return ret; ++} ++ ++static int yt8010_config_aneg(struct phy_device *phydev) ++{ ++ phydev->speed = SPEED_100; ++ return 0; ++} ++ ++static int yt8512_clk_init(struct phy_device *phydev) ++{ ++ int ret; ++ int val; ++ ++ val = ytphy_read_ext(phydev, YT8512_EXTREG_AFE_PLL); ++ if (val < 0) ++ return val; ++ ++ val |= YT8512_CONFIG_PLL_REFCLK_SEL_EN; ++ ++ ret = ytphy_write_ext(phydev, YT8512_EXTREG_AFE_PLL, val); ++ if (ret < 0) ++ return ret; ++ ++ val = ytphy_read_ext(phydev, YT8512_EXTREG_EXTEND_COMBO); ++ if (val < 0) ++ return val; ++ ++ val |= YT8512_CONTROL1_RMII_EN; ++ ++ ret = ytphy_write_ext(phydev, YT8512_EXTREG_EXTEND_COMBO, val); ++ if (ret < 0) ++ return ret; ++ ++ val = phy_read(phydev, MII_BMCR); ++ if (val < 0) ++ return val; ++ ++ val |= YT_SOFTWARE_RESET; ++ ret = phy_write(phydev, MII_BMCR, val); ++ ++ return ret; ++} ++ ++static int yt8512_led_init(struct phy_device *phydev) ++{ ++ int ret; ++ int val; ++ int mask; ++ ++ val = ytphy_read_ext(phydev, YT8512_EXTREG_LED0); ++ if (val < 0) ++ return val; ++ ++ val |= YT8512_LED0_ACT_BLK_IND; ++ ++ mask = YT8512_LED0_DIS_LED_AN_TRY | YT8512_LED0_BT_BLK_EN | ++ YT8512_LED0_HT_BLK_EN | YT8512_LED0_COL_BLK_EN | ++ YT8512_LED0_BT_ON_EN; ++ val &= ~mask; ++ ++ ret = ytphy_write_ext(phydev, YT8512_EXTREG_LED0, val); ++ if (ret < 0) ++ return ret; ++ ++ val = ytphy_read_ext(phydev, YT8512_EXTREG_LED1); ++ if (val < 0) ++ return val; ++ ++ val |= YT8512_LED1_BT_ON_EN; ++ ++ mask = YT8512_LED1_TXACT_BLK_EN | YT8512_LED1_RXACT_BLK_EN; ++ val &= ~mask; ++ ++ ret = ytphy_write_ext(phydev, YT8512_LED1_BT_ON_EN, val); ++ ++ return ret; ++} ++ ++static int yt8512_config_init(struct phy_device *phydev) ++{ ++ int ret; ++ int val; ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ ret = ytphy_config_init(phydev); ++#else ++ ret = genphy_config_init(phydev); ++#endif ++ if (ret < 0) ++ return ret; ++ ++ ret = yt8512_clk_init(phydev); ++ if (ret < 0) ++ return ret; ++ ++ ret = yt8512_led_init(phydev); ++ ++ /* disable auto sleep */ ++ val = ytphy_read_ext(phydev, YT8512_EXTREG_SLEEP_CONTROL1); ++ if (val < 0) ++ return val; ++ ++ val &= (~BIT(YT8512_EN_SLEEP_SW_BIT)); ++ ++ ret = ytphy_write_ext(phydev, YT8512_EXTREG_SLEEP_CONTROL1, val); ++ if (ret < 0) ++ return ret; ++ ++ return ret; ++} ++ ++static int yt8512_read_status(struct phy_device *phydev) ++{ ++ int ret; ++ int val; ++ int speed, speed_mode, duplex; ++ ++ ret = genphy_update_link(phydev); ++ if (ret) ++ return ret; ++ ++ val = phy_read(phydev, REG_PHY_SPEC_STATUS); ++ if (val < 0) ++ return val; ++ ++ duplex = (val & YT8512_DUPLEX) >> YT8512_DUPLEX_BIT; ++ speed_mode = (val & YT8512_SPEED_MODE) >> YT8512_SPEED_MODE_BIT; ++ switch (speed_mode) { ++ case 0: ++ speed = SPEED_10; ++ break; ++ case 1: ++ speed = SPEED_100; ++ break; ++ case 2: ++ case 3: ++ default: ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ speed = -1; ++#else ++ speed = SPEED_UNKNOWN; ++#endif ++ break; ++ } ++ ++ phydev->speed = speed; ++ phydev->duplex = duplex; ++ ++ return 0; ++} ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++#else ++#if 0 ++int yt8521_soft_reset(struct phy_device *phydev) ++{ ++ int ret; ++ ++ ytphy_write_ext(phydev, 0xa000, 0); ++ ret = genphy_soft_reset(phydev); ++ if (ret < 0) ++ return ret; ++ ++ ytphy_write_ext(phydev, 0xa000, 2); ++ ret = genphy_soft_reset(phydev); ++ if (ret < 0) { ++ ytphy_write_ext(phydev, 0xa000, 0); ++ return ret; ++ } ++ ++ return 0; ++} ++#else ++/* qingsong feedback 2 genphy_soft_reset will cause problem. ++ * and this is the reduction version ++ */ ++int yt8521_soft_reset(struct phy_device *phydev) ++{ ++ int ret, val; ++ ++ val = ytphy_read_ext(phydev, 0xa001); ++ ytphy_write_ext(phydev, 0xa001, (val & ~0x8000)); ++ ++ ret = genphy_soft_reset(phydev); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++#endif ++ ++#endif ++ ++#if GMAC_CLOCK_INPUT_NEEDED ++static int ytphy_mii_rd_ext(struct mii_bus *bus, int phy_id, u32 regnum) ++{ ++ int ret; ++ int val; ++ ++ ret = bus->write(bus, phy_id, REG_DEBUG_ADDR_OFFSET, regnum); ++ if (ret < 0) ++ return ret; ++ ++ val = bus->read(bus, phy_id, REG_DEBUG_DATA); ++ ++ return val; ++} ++ ++static int ytphy_mii_wr_ext(struct mii_bus *bus, int phy_id, u32 regnum, u16 val) ++{ ++ int ret; ++ ++ ret = bus->write(bus, phy_id, REG_DEBUG_ADDR_OFFSET, regnum); ++ if (ret < 0) ++ return ret; ++ ++ ret = bus->write(bus, phy_id, REG_DEBUG_DATA, val); ++ ++ return ret; ++} ++ ++int yt8511_config_dis_txdelay(struct mii_bus *bus, int phy_id) ++{ ++ int ret; ++ int val; ++ ++ /* disable auto sleep */ ++ val = ytphy_mii_rd_ext(bus, phy_id, 0x27); ++ if (val < 0) ++ return val; ++ ++ val &= (~BIT(15)); ++ ++ ret = ytphy_mii_wr_ext(bus, phy_id, 0x27, val); ++ if (ret < 0) ++ return ret; ++ ++ /* enable RXC clock when no wire plug */ ++ val = ytphy_mii_rd_ext(bus, phy_id, 0xc); ++ if (val < 0) ++ return val; ++ ++ /* ext reg 0xc b[7:4] ++ Tx Delay time = 150ps * N - 250ps ++ */ ++ val &= ~(0xf << 4); ++ ret = ytphy_mii_wr_ext(bus, phy_id, 0xc, val); ++ printk("yt8511_config_dis_txdelay..phy txdelay, val=%#08x\n",val); ++ ++ return ret; ++} ++ ++int phy_yt8531_led_fixup(struct mii_bus *bus, int addr) ++{ ++ printk("%s in\n", __func__); ++ ++ ytphy_mii_wr_ext(bus, addr, 0xa00d, 0x670); ++ ytphy_mii_wr_ext(bus, addr, 0xa00e, 0x2070); ++ ytphy_mii_wr_ext(bus, addr, 0xa00f, 0x7e); ++ ++ return 0; ++} ++ ++int yt8511_config_out_125m(struct mii_bus *bus, int addr) ++{ ++ int ret; ++ int val; ++ ++ mdelay(50); ++ ret = ytphy_mii_wr_ext(bus, addr, 0xa012, 0xd0); ++ ++ mdelay(100); ++ val = ytphy_mii_rd_ext(bus, addr, 0xa012); ++ ++ if(val != 0xd0) ++ { ++ printk("yt8511_config_out_125m error\n"); ++ return -1; ++ } ++ ++ /* disable auto sleep */ ++ val = ytphy_mii_rd_ext(bus, addr, 0x27); ++ if (val < 0) ++ return val; ++ ++ val &= (~BIT(15)); ++ ++ ret = ytphy_mii_wr_ext(bus, addr, 0x27, val); ++ if (ret < 0) ++ return ret; ++ ++ /* enable RXC clock when no wire plug */ ++ val = ytphy_mii_rd_ext(bus, addr, 0xc); ++ if (val < 0) ++ return val; ++ ++ /* ext reg 0xc.b[2:1] ++ 00-----25M from pll; ++ 01---- 25M from xtl;(default) ++ 10-----62.5M from pll; ++ 11----125M from pll(here set to this value) ++ */ ++ val |= (3 << 1); ++ ret = ytphy_mii_wr_ext(bus, addr, 0xc, val); ++ printk("yt8511_config_out_125m, phy clk out, val=%#08x\n",val); ++ ++#if 0 ++ /* for customer, please enable it based on demand. ++ * configure to master ++ */ ++ val = bus->read(bus, phy_id, 0x9/*master/slave config reg*/); ++ val |= (0x3<<11); //to be manual config and force to be master ++ ret = bus->write(bus, phy_id, 0x9, val); //take effect until phy soft reset ++ if (ret < 0) ++ return ret; ++ ++ printk("yt8511_config_out_125m, phy to be master, val=%#08x\n",val); ++#endif ++ ++ return ret; ++} ++ ++EXPORT_SYMBOL(yt8511_config_out_125m); + + static int yt8511_config_init(struct phy_device *phydev) + { +- int oldpage, ret = 0; +- unsigned int ge, fe; ++ int ret; ++ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ ret = ytphy_config_init(phydev); ++#else ++ ret = genphy_config_init(phydev); ++#endif ++ ++ return ret; ++} ++#endif /*GMAC_CLOCK_INPUT_NEEDED*/ ++ ++#if (YTPHY_ENABLE_WOL) ++static int ytphy_switch_reg_space(struct phy_device *phydev, int space) ++{ ++ int ret; ++ ++ if (space == YTPHY_REG_SPACE_UTP){ ++ ret = ytphy_write_ext(phydev, 0xa000, 0); ++ }else{ ++ ret = ytphy_write_ext(phydev, 0xa000, 2); ++ } ++ ++ return ret; ++} ++ ++static int ytphy_wol_en_cfg(struct phy_device *phydev, ytphy_wol_cfg_t wol_cfg) ++{ ++ int ret=0; ++ int val=0; ++ ++ val = ytphy_read_ext(phydev, YTPHY_WOL_CFG_REG); ++ if (val < 0) ++ return val; ++ ++ if(wol_cfg.enable) { ++ val |= YTPHY_WOL_CFG_EN; ++ ++ if(wol_cfg.type == YTPHY_WOL_TYPE_LEVEL) { ++ val &= ~YTPHY_WOL_CFG_TYPE; ++ val &= ~YTPHY_WOL_CFG_INTR_SEL; ++ } else if(wol_cfg.type == YTPHY_WOL_TYPE_PULSE) { ++ val |= YTPHY_WOL_CFG_TYPE; ++ val |= YTPHY_WOL_CFG_INTR_SEL; ++ ++ if(wol_cfg.width == YTPHY_WOL_WIDTH_84MS) { ++ val &= ~YTPHY_WOL_CFG_WIDTH1; ++ val &= ~YTPHY_WOL_CFG_WIDTH2; ++ } else if(wol_cfg.width == YTPHY_WOL_WIDTH_168MS) { ++ val |= YTPHY_WOL_CFG_WIDTH1; ++ val &= ~YTPHY_WOL_CFG_WIDTH2; ++ } else if(wol_cfg.width == YTPHY_WOL_WIDTH_336MS) { ++ val &= ~YTPHY_WOL_CFG_WIDTH1; ++ val |= YTPHY_WOL_CFG_WIDTH2; ++ } else if(wol_cfg.width == YTPHY_WOL_WIDTH_672MS) { ++ val |= YTPHY_WOL_CFG_WIDTH1; ++ val |= YTPHY_WOL_CFG_WIDTH2; ++ } ++ } ++ } else { ++ val &= ~YTPHY_WOL_CFG_EN; ++ val &= ~YTPHY_WOL_CFG_INTR_SEL; ++ } ++ ++ ret = ytphy_write_ext(phydev, YTPHY_WOL_CFG_REG, val); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static void ytphy_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) ++{ ++ int val = 0; ++ ++ wol->supported = WAKE_MAGIC; ++ wol->wolopts = 0; ++ ++ val = ytphy_read_ext(phydev, YTPHY_WOL_CFG_REG); ++ if (val < 0) ++ return; ++ ++ if (val & YTPHY_WOL_CFG_EN) ++ wol->wolopts |= WAKE_MAGIC; ++ ++ return; ++} ++ ++static int ytphy_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) ++{ ++ int ret, pre_page, val; ++ ytphy_wol_cfg_t wol_cfg; ++ struct net_device *p_attached_dev = phydev->attached_dev; ++ ++ memset(&wol_cfg,0,sizeof(ytphy_wol_cfg_t)); ++ pre_page = ytphy_read_ext(phydev, 0xa000); ++ if (pre_page < 0) ++ return pre_page; ++ ++ /* Switch to phy UTP page */ ++ ret = ytphy_switch_reg_space(phydev, YTPHY_REG_SPACE_UTP); ++ if (ret < 0) ++ return ret; ++ ++ if (wol->wolopts & WAKE_MAGIC) { ++ ++ /* Enable the WOL interrupt */ ++ val = phy_read(phydev, YTPHY_UTP_INTR_REG); ++ val |= YTPHY_WOL_INTR; ++ ret = phy_write(phydev, YTPHY_UTP_INTR_REG, val); ++ if (ret < 0) ++ return ret; ++ ++ /* Set the WOL config */ ++ wol_cfg.enable = 1; //enable ++ wol_cfg.type= YTPHY_WOL_TYPE_PULSE; ++ wol_cfg.width= YTPHY_WOL_WIDTH_672MS; ++ ret = ytphy_wol_en_cfg(phydev, wol_cfg); ++ if (ret < 0) ++ return ret; ++ ++ /* Store the device address for the magic packet */ ++ ret = ytphy_write_ext(phydev, YTPHY_MAGIC_PACKET_MAC_ADDR2, ++ ((p_attached_dev->dev_addr[0] << 8) | ++ p_attached_dev->dev_addr[1])); ++ if (ret < 0) ++ return ret; ++ ret = ytphy_write_ext(phydev, YTPHY_MAGIC_PACKET_MAC_ADDR1, ++ ((p_attached_dev->dev_addr[2] << 8) | ++ p_attached_dev->dev_addr[3])); ++ if (ret < 0) ++ return ret; ++ ret = ytphy_write_ext(phydev, YTPHY_MAGIC_PACKET_MAC_ADDR0, ++ ((p_attached_dev->dev_addr[4] << 8) | ++ p_attached_dev->dev_addr[5])); ++ if (ret < 0) ++ return ret; ++ } else { ++ wol_cfg.enable = 0; //disable ++ wol_cfg.type= YTPHY_WOL_TYPE_MAX; ++ wol_cfg.width= YTPHY_WOL_WIDTH_MAX; ++ ret = ytphy_wol_en_cfg(phydev, wol_cfg); ++ if (ret < 0) ++ return ret; ++ } ++ ++ /* Recover to previous register space page */ ++ ret = ytphy_switch_reg_space(phydev, pre_page); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++#endif /*(YTPHY_ENABLE_WOL)*/ ++ ++static int yt8521_config_init(struct phy_device *phydev) ++{ ++ int ret; ++ int val; + +- oldpage = phy_select_page(phydev, YT8511_EXT_CLK_GATE); +- if (oldpage < 0) +- goto err_restore_page; ++ phydev->irq = PHY_POLL; + +- /* set rgmii delay mode */ +- switch (phydev->interface) { +- case PHY_INTERFACE_MODE_RGMII: +- ge = YT8511_DELAY_GE_TX_DIS; +- fe = YT8511_DELAY_FE_TX_DIS; ++ ytphy_write_ext(phydev, 0xa000, 0); ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ ret = ytphy_config_init(phydev); ++#else ++ ret = genphy_config_init(phydev); ++#endif ++ if (ret < 0) ++ return ret; ++ ++ /* disable auto sleep */ ++ val = ytphy_read_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1); ++ if (val < 0) ++ return val; ++ ++ val &= (~BIT(YT8521_EN_SLEEP_SW_BIT)); ++ ++ ret = ytphy_write_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1, val); ++ if (ret < 0) ++ return ret; ++ ++ /* enable RXC clock when no wire plug */ ++ ret = ytphy_write_ext(phydev, 0xa000, 0); ++ if (ret < 0) ++ return ret; ++ ++ val = ytphy_read_ext(phydev, 0xc); ++ if (val < 0) ++ return val; ++ val &= ~(1 << 12); ++ ret = ytphy_write_ext(phydev, 0xc, val); ++ if (ret < 0) ++ return ret; ++ ++ printk (KERN_INFO "yt8521_config_init, 8521 init call out.\n"); ++ return ret; ++} ++ ++/* ++ * for fiber mode, there is no 10M speed mode and ++ * this function is for this purpose. ++ */ ++static int yt8521_adjust_status(struct phy_device *phydev, int val, int is_utp) ++{ ++ int speed_mode, duplex; ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ int speed = -1; ++#else ++ int speed = SPEED_UNKNOWN; ++#endif ++ ++ duplex = (val & YT8512_DUPLEX) >> YT8521_DUPLEX_BIT; ++ speed_mode = (val & YT8521_SPEED_MODE) >> YT8521_SPEED_MODE_BIT; ++ switch (speed_mode) { ++ case 0: ++ if (is_utp) ++ speed = SPEED_10; + break; +- case PHY_INTERFACE_MODE_RGMII_RXID: +- ge = YT8511_DELAY_RX | YT8511_DELAY_GE_TX_DIS; +- fe = YT8511_DELAY_FE_TX_DIS; ++ case 1: ++ speed = SPEED_100; + break; +- case PHY_INTERFACE_MODE_RGMII_TXID: +- ge = YT8511_DELAY_GE_TX_EN; +- fe = YT8511_DELAY_FE_TX_EN; ++ case 2: ++ speed = SPEED_1000; + break; +- case PHY_INTERFACE_MODE_RGMII_ID: +- ge = YT8511_DELAY_RX | YT8511_DELAY_GE_TX_EN; +- fe = YT8511_DELAY_FE_TX_EN; ++ case 3: + break; +- default: /* do not support other modes */ +- ret = -EOPNOTSUPP; +- goto err_restore_page; ++ default: ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ speed = -1; ++#else ++ speed = SPEED_UNKNOWN; ++#endif ++ break; ++ } ++ ++ phydev->speed = speed; ++ phydev->duplex = duplex; ++ //printk (KERN_INFO "yt8521_adjust_status call out,regval=0x%04x,mode=%s,speed=%dm...\n", val,is_utp?"utp":"fiber", phydev->speed); ++ ++ return 0; ++} ++ ++/* ++ * for fiber mode, when speed is 100M, there is no definition for autonegotiation, and ++ * this function handles this case and return 1 per linux kernel's polling. ++ */ ++int yt8521_aneg_done (struct phy_device *phydev) ++{ ++ ++ //printk("yt8521_aneg_done callin,speed=%dm,linkmoded=%d\n", phydev->speed,link_mode_8521); ++ ++ if((32 == link_mode_8521) && (SPEED_100 == phydev->speed)) ++ { ++ return 1/*link_mode_8521*/; ++ } ++ ++#if ( LINUX_VERSION_CODE > KERNEL_VERSION(3,11,0) ) ++ return genphy_aneg_done(phydev); ++#else ++ return 1; ++#endif ++} ++ ++static int yt8521_read_status(struct phy_device *phydev) ++{ ++ int ret; ++ volatile int val, yt8521_fiber_latch_val, yt8521_fiber_curr_val; ++ volatile int link; ++ int link_utp = 0, link_fiber = 0; ++ ++#if (YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER) ++ /* reading UTP */ ++ ret = ytphy_write_ext(phydev, 0xa000, 0); ++ if (ret < 0) ++ return ret; ++ ++ val = phy_read(phydev, REG_PHY_SPEC_STATUS); ++ if (val < 0) ++ return val; ++ ++ link = val & (BIT(YT8521_LINK_STATUS_BIT)); ++ if (link) { ++ link_utp = 1; ++ link_mode_8521 = 1; ++ yt8521_adjust_status(phydev, val, 1); ++ } else { ++ link_utp = 0; ++ } ++#endif //(YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER) ++ ++#if (YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_UTP) ++ /* reading Fiber */ ++ ret = ytphy_write_ext(phydev, 0xa000, 2); ++ if (ret < 0) ++ return ret; ++ ++ val = phy_read(phydev, REG_PHY_SPEC_STATUS); ++ if (val < 0) ++ return val; ++ ++ //note: below debug information is used to check multiple PHy ports. ++ //printk (KERN_INFO "yt8521_read_status, fiber status=%04x,macbase=0x%08lx\n", val,(unsigned long)phydev->attached_dev); ++ ++ /* for fiber, from 1000m to 100m, there is not link down from 0x11, and check reg 1 to identify such case ++ * this is important for Linux kernel for that, missing linkdown event will cause problem. ++ */ ++ yt8521_fiber_latch_val = phy_read(phydev, MII_BMSR); ++ yt8521_fiber_curr_val = phy_read(phydev, MII_BMSR); ++ link = val & (BIT(YT8521_LINK_STATUS_BIT)); ++ if((link) && (yt8521_fiber_latch_val != yt8521_fiber_curr_val)) ++ { ++ link = 0; ++ printk (KERN_INFO "yt8521_read_status, fiber link down detect,latch=%04x,curr=%04x\n", yt8521_fiber_latch_val,yt8521_fiber_curr_val); ++ } ++ ++ if (link) { ++ link_fiber = 1; ++ yt8521_adjust_status(phydev, val, 0); ++ link_mode_8521 = 32; //fiber mode ++ ++ ++ } else { ++ link_fiber = 0; ++ } ++#endif //(YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_UTP) ++ ++ if (link_utp || link_fiber) { ++ phydev->link = 1; ++ } else { ++ phydev->link = 0; ++ link_mode_8521 = 0; ++ } ++ ++#if (YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER) ++ if (link_utp) { ++ ytphy_write_ext(phydev, 0xa000, 0); + } ++#endif + +- ret = __phy_modify(phydev, YT8511_PAGE, (YT8511_DELAY_RX | YT8511_DELAY_GE_TX_EN), ge); ++ //printk (KERN_INFO "yzhang..8521 read status call out,link=%d,linkmode=%d\n", phydev->link, link_mode_8521 ); ++ return 0; ++} ++ ++int yt8521_suspend(struct phy_device *phydev) ++{ ++#if !(SYS_WAKEUP_BASED_ON_ETH_PKT) ++ int value; ++ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ mutex_lock(&phydev->lock); ++#else ++ /* no need lock in 4.19 */ ++#endif ++ ++ ytphy_write_ext(phydev, 0xa000, 0); ++ value = phy_read(phydev, MII_BMCR); ++ phy_write(phydev, MII_BMCR, value | BMCR_PDOWN); ++ ++ ytphy_write_ext(phydev, 0xa000, 2); ++ value = phy_read(phydev, MII_BMCR); ++ phy_write(phydev, MII_BMCR, value | BMCR_PDOWN); ++ ++ ytphy_write_ext(phydev, 0xa000, 0); ++ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ mutex_unlock(&phydev->lock); ++#else ++ /* no need lock/unlock in 4.19 */ ++#endif ++#endif /*!(SYS_WAKEUP_BASED_ON_ETH_PKT)*/ ++ ++ return 0; ++} ++ ++int yt8521_resume(struct phy_device *phydev) ++{ ++#if !(SYS_WAKEUP_BASED_ON_ETH_PKT) ++ int value; ++ int ret; ++ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ mutex_lock(&phydev->lock); ++#else ++ /* no need lock/unlock in 4.19 */ ++#endif ++ ++ ytphy_write_ext(phydev, 0xa000, 0); ++ value = phy_read(phydev, MII_BMCR); ++ phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN); ++ ++ /* disable auto sleep */ ++ value = ytphy_read_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1); ++ if (value < 0) ++ return value; ++ ++ value &= (~BIT(YT8521_EN_SLEEP_SW_BIT)); ++ ret = ytphy_write_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1, value); + if (ret < 0) +- goto err_restore_page; ++ return ret; + +- /* set clock mode to 125mhz */ +- ret = __phy_modify(phydev, YT8511_PAGE, 0, YT8511_CLK_125M); ++ /* enable RXC clock when no wire plug */ ++ value = ytphy_read_ext(phydev, 0xc); ++ if (value < 0) ++ return value; ++ value &= ~(1 << 12); ++ ret = ytphy_write_ext(phydev, 0xc, value); + if (ret < 0) +- goto err_restore_page; ++ return ret; ++ ++ ytphy_write_ext(phydev, 0xa000, 2); ++ value = phy_read(phydev, MII_BMCR); ++ phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN); ++ ++#if (YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER) ++ ytphy_write_ext(phydev, 0xa000, 0); ++#endif ++ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ mutex_unlock(&phydev->lock); ++#else ++ /* no need lock/unlock in 4.19 */ ++#endif ++#endif /*!(SYS_WAKEUP_BASED_ON_ETH_PKT)*/ ++ ++ return 0; ++} + +- /* fast ethernet delay is in a separate page */ +- ret = __phy_write(phydev, YT8511_PAGE_SELECT, YT8511_EXT_DELAY_DRIVE); ++ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++#else ++int yt8618_soft_reset(struct phy_device *phydev) ++{ ++ int ret; ++ ++ ytphy_write_ext(phydev, 0xa000, 0); ++ ret = genphy_soft_reset(phydev); + if (ret < 0) +- goto err_restore_page; ++ return ret; + +- ret = __phy_modify(phydev, YT8511_PAGE, YT8511_DELAY_FE_TX_EN, fe); ++ return 0; ++} ++ ++int yt8614_soft_reset(struct phy_device *phydev) ++{ ++ int ret; ++ ++ /* utp */ ++ ytphy_write_ext(phydev, 0xa000, 0); ++ ret = genphy_soft_reset(phydev); + if (ret < 0) +- goto err_restore_page; ++ return ret; ++ ++ /* qsgmii */ ++ ytphy_write_ext(phydev, 0xa000, 2); ++ ret = genphy_soft_reset(phydev); ++ if (ret < 0) { ++ ytphy_write_ext(phydev, 0xa000, 0); //back to utp mode ++ return ret; ++ } ++ ++ /* sgmii */ ++ ytphy_write_ext(phydev, 0xa000, 3); ++ ret = genphy_soft_reset(phydev); ++ if (ret < 0) { ++ ytphy_write_ext(phydev, 0xa000, 0); //back to utp mode ++ return ret; ++ } + +- /* leave pll enabled in sleep */ +- ret = __phy_write(phydev, YT8511_PAGE_SELECT, YT8511_EXT_SLEEP_CTRL); ++ return 0; ++} ++ ++#endif ++ ++static int yt8618_config_init(struct phy_device *phydev) ++{ ++ int ret; ++ int val; ++ ++ phydev->irq = PHY_POLL; ++ ++ if(0xff == yt_mport_base_phy_addr) ++ /* by default, we think the first phy should be the base phy addr. for mul */ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ { ++ yt_mport_base_phy_addr = phydev->addr; ++ }else if (yt_mport_base_phy_addr > phydev->addr) { ++ printk (KERN_INFO "yzhang..8618 init, phy address mismatch, base=%d, cur=%d\n", yt_mport_base_phy_addr, phydev->addr); ++ } ++#else ++ { ++ yt_mport_base_phy_addr = phydev->mdio.addr; ++ }else if (yt_mport_base_phy_addr > phydev->mdio.addr) { ++ printk (KERN_INFO "yzhang..8618 init, phy address mismatch, base=%d, cur=%d\n", yt_mport_base_phy_addr, phydev->mdio.addr); ++ } ++#endif ++ ++ ytphy_write_ext(phydev, 0xa000, 0); ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ ret = ytphy_config_init(phydev); ++#else ++ ret = genphy_config_init(phydev); ++#endif + if (ret < 0) +- goto err_restore_page; ++ return ret; + +- ret = __phy_modify(phydev, YT8511_PAGE, 0, YT8511_PLLON_SLP); ++ /* for utp to optimize signal */ ++ ret = ytphy_write_ext(phydev, 0x41, 0x33); ++ if (ret < 0) ++ return ret; ++ ret = ytphy_write_ext(phydev, 0x42, 0x66); + if (ret < 0) +- goto err_restore_page; ++ return ret; ++ ret = ytphy_write_ext(phydev, 0x43, 0xaa); ++ if (ret < 0) ++ return ret; ++ ret = ytphy_write_ext(phydev, 0x44, 0xd0d); ++ if (ret < 0) ++ return ret; ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ if((phydev->addr > yt_mport_base_phy_addr) && ((2 == phydev->addr - yt_mport_base_phy_addr) || (5 == phydev->addr - yt_mport_base_phy_addr))) ++#else ++ if((phydev->mdio.addr > yt_mport_base_phy_addr) && ((2 == phydev->mdio.addr - yt_mport_base_phy_addr) || (5 == phydev->mdio.addr - yt_mport_base_phy_addr))) ++#endif ++ { ++ ret = ytphy_write_ext(phydev, 0x44, 0x2929); ++ if (ret < 0) ++ return ret; ++ } ++ ++ val = phy_read(phydev, MII_BMCR); ++ phy_write(phydev, MII_BMCR, val | BMCR_RESET); + +-err_restore_page: +- return phy_restore_page(phydev, oldpage, ret); ++ printk (KERN_INFO "yt8618_config_init call out.\n"); ++ return ret; + } + +-static struct phy_driver motorcomm_phy_drvs[] = { ++static int yt8614_config_init(struct phy_device *phydev) ++{ ++ int ret = 0; ++ ++ phydev->irq = PHY_POLL; ++ ++ if(0xff == yt_mport_base_phy_addr_8614) ++ /* by default, we think the first phy should be the base phy addr. for mul */ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) + { +- PHY_ID_MATCH_EXACT(PHY_ID_YT8511), ++ yt_mport_base_phy_addr_8614 = (unsigned int)phydev->addr; ++ }else if (yt_mport_base_phy_addr_8614 > (unsigned int)phydev->addr) { ++ printk (KERN_INFO "yzhang..8618 init, phy address mismatch, base=%u, cur=%d\n", yt_mport_base_phy_addr_8614, phydev->addr); ++ } ++#else ++ { ++ yt_mport_base_phy_addr_8614 = (unsigned int)phydev->mdio.addr; ++ }else if (yt_mport_base_phy_addr_8614 > (unsigned int)phydev->mdio.addr) { ++ printk (KERN_INFO "yzhang..8618 init, phy address mismatch, base=%u, cur=%d\n", yt_mport_base_phy_addr_8614, phydev->mdio.addr); ++ } ++#endif ++ return ret; ++} ++ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++#define yt8614_get_port_from_phydev(phydev) ((0xff == yt_mport_base_phy_addr_8614) && (yt_mport_base_phy_addr_8614 <= (phydev)->addr) ? 0 : (unsigned int)((phydev)->addr) - yt_mport_base_phy_addr_8614) ++#else ++#define yt8614_get_port_from_phydev(phydev) ((0xff == yt_mport_base_phy_addr_8614) && (yt_mport_base_phy_addr_8614 <= (phydev)->mdio.addr) ? 0 : (unsigned int)((phydev)->mdio.addr) - yt_mport_base_phy_addr_8614) ++#endif ++ ++int yt8618_aneg_done (struct phy_device *phydev) ++{ ++ ++ return genphy_aneg_done(phydev); ++} ++ ++int yt8614_aneg_done (struct phy_device *phydev) ++{ ++ int port = yt8614_get_port_from_phydev(phydev); ++ ++ /*it should be used for 8614 fiber*/ ++ if((32 == link_mode_8614[port]) && (SPEED_100 == phydev->speed)) ++ { ++ return 1; ++ } ++ ++ return genphy_aneg_done(phydev); ++} ++ ++static int yt8614_read_status(struct phy_device *phydev) ++{ ++ //int i; ++ int ret; ++ volatile int val, yt8614_fiber_latch_val, yt8614_fiber_curr_val; ++ volatile int link; ++ int link_utp = 0, link_fiber = 0; ++ int port = yt8614_get_port_from_phydev(phydev); ++ ++#if (YT8614_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER) ++ /* switch to utp and reading regs */ ++ ret = ytphy_write_ext(phydev, 0xa000, 0); ++ if (ret < 0) ++ return ret; ++ ++ val = phy_read(phydev, REG_PHY_SPEC_STATUS); ++ if (val < 0) ++ return val; ++ ++ link = val & (BIT(YT8521_LINK_STATUS_BIT)); ++ if (link) { ++ link_utp = 1; ++ // here is same as 8521 and re-use the function; ++ yt8521_adjust_status(phydev, val, 1); ++ } else { ++ link_utp = 0; ++ } ++#endif //(YT8614_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER) ++ ++#if (YT8614_PHY_MODE_CURR != YT8521_PHY_MODE_UTP) ++ /* reading Fiber/sgmii */ ++ ret = ytphy_write_ext(phydev, 0xa000, 3); ++ if (ret < 0) ++ return ret; ++ ++ val = phy_read(phydev, REG_PHY_SPEC_STATUS); ++ if (val < 0) ++ return val; ++ ++ //printk (KERN_INFO "yzhang..8614 read fiber status=%04x,macbase=0x%08lx\n", val,(unsigned long)phydev->attached_dev); ++ ++ /* for fiber, from 1000m to 100m, there is not link down from 0x11, and check reg 1 to identify such case */ ++ yt8614_fiber_latch_val = phy_read(phydev, MII_BMSR); ++ yt8614_fiber_curr_val = phy_read(phydev, MII_BMSR); ++ link = val & (BIT(YT8521_LINK_STATUS_BIT)); ++ if((link) && (yt8614_fiber_latch_val != yt8614_fiber_curr_val)) ++ { ++ link = 0; ++ printk (KERN_INFO "yt8614_read_status, fiber link down detect,latch=%04x,curr=%04x\n", yt8614_fiber_latch_val,yt8614_fiber_curr_val); ++ } ++ ++ if (link) { ++ link_fiber = 1; ++ yt8521_adjust_status(phydev, val, 0); ++ link_mode_8614[port] = 32; //fiber mode ++ ++ ++ } else { ++ link_fiber = 0; ++ } ++#endif //(YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_UTP) ++ ++ if (link_utp || link_fiber) { ++ phydev->link = 1; ++ } else { ++ phydev->link = 0; ++ link_mode_8614[port] = 0; ++ } ++ ++#if (YT8614_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER) ++ if (link_utp) { ++ ytphy_write_ext(phydev, 0xa000, 0); ++ } ++#endif ++ //printk (KERN_INFO "yt8614_read_status call out,link=%d,linkmode=%d\n", phydev->link, link_mode_8614[port] ); ++ ++ return 0; ++} ++ ++static int yt8618_read_status(struct phy_device *phydev) ++{ ++ int ret; ++ volatile int val; //maybe for 8614 yt8521_fiber_latch_val, yt8521_fiber_curr_val; ++ volatile int link; ++ int link_utp = 0, link_fiber = 0; ++ ++ /* switch to utp and reading regs */ ++ ret = ytphy_write_ext(phydev, 0xa000, 0); ++ if (ret < 0) ++ return ret; ++ ++ val = phy_read(phydev, REG_PHY_SPEC_STATUS); ++ if (val < 0) ++ return val; ++ ++ link = val & (BIT(YT8521_LINK_STATUS_BIT)); ++ if (link) { ++ link_utp = 1; ++ yt8521_adjust_status(phydev, val, 1); ++ } else { ++ link_utp = 0; ++ } ++ ++ if (link_utp || link_fiber) { ++ phydev->link = 1; ++ } else { ++ phydev->link = 0; ++ } ++ ++ return 0; ++} ++ ++int yt8618_suspend(struct phy_device *phydev) ++{ ++#if !(SYS_WAKEUP_BASED_ON_ETH_PKT) ++ int value; ++ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ mutex_lock(&phydev->lock); ++#else ++ /* no need lock in 4.19 */ ++#endif ++ ++ ytphy_write_ext(phydev, 0xa000, 0); ++ value = phy_read(phydev, MII_BMCR); ++ phy_write(phydev, MII_BMCR, value | BMCR_PDOWN); ++ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ mutex_unlock(&phydev->lock); ++#else ++ /* no need lock/unlock in 4.19 */ ++#endif ++#endif /*!(SYS_WAKEUP_BASED_ON_ETH_PKT)*/ ++ ++ return 0; ++} ++ ++int yt8618_resume(struct phy_device *phydev) ++{ ++#if !(SYS_WAKEUP_BASED_ON_ETH_PKT) ++ int value; ++ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ mutex_lock(&phydev->lock); ++#else ++ /* no need lock/unlock in 4.19 */ ++#endif ++ ++ ytphy_write_ext(phydev, 0xa000, 0); ++ value = phy_read(phydev, MII_BMCR); ++ phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN); ++ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ mutex_unlock(&phydev->lock); ++#else ++ /* no need lock/unlock in 4.19 */ ++#endif ++#endif /*!(SYS_WAKEUP_BASED_ON_ETH_PKT)*/ ++ ++ return 0; ++} ++ ++int yt8614_suspend(struct phy_device *phydev) ++{ ++#if !(SYS_WAKEUP_BASED_ON_ETH_PKT) ++ int value; ++ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ mutex_lock(&phydev->lock); ++#else ++ /* no need lock in 4.19 */ ++#endif ++ ++ ytphy_write_ext(phydev, 0xa000, 0); ++ value = phy_read(phydev, MII_BMCR); ++ phy_write(phydev, MII_BMCR, value | BMCR_PDOWN); ++ ++ ytphy_write_ext(phydev, 0xa000, 3); ++ value = phy_read(phydev, MII_BMCR); ++ phy_write(phydev, MII_BMCR, value | BMCR_PDOWN); ++ ++ ytphy_write_ext(phydev, 0xa000, 0); ++ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ mutex_unlock(&phydev->lock); ++#else ++ /* no need lock/unlock in 4.19 */ ++#endif ++#endif /*!(SYS_WAKEUP_BASED_ON_ETH_PKT)*/ ++ ++ return 0; ++} ++ ++int yt8614_resume(struct phy_device *phydev) ++{ ++#if !(SYS_WAKEUP_BASED_ON_ETH_PKT) ++ int value; ++ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ mutex_lock(&phydev->lock); ++#else ++ /* no need lock/unlock in 4.19 */ ++#endif ++ ++ ytphy_write_ext(phydev, 0xa000, 0); ++ value = phy_read(phydev, MII_BMCR); ++ phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN); ++ ++ ytphy_write_ext(phydev, 0xa000, 3); ++ value = phy_read(phydev, MII_BMCR); ++ phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN); ++ ++ ytphy_write_ext(phydev, 0xa000, 0); ++ ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ mutex_unlock(&phydev->lock); ++#else ++ /* no need lock/unlock in 4.19 */ ++#endif ++#endif /*!(SYS_WAKEUP_BASED_ON_ETH_PKT)*/ ++ ++ return 0; ++} ++ ++ ++static struct phy_driver ytphy_drvs[] = { ++ { ++ .phy_id = PHY_ID_YT8010, ++ .name = "YT8010 Automotive Ethernet", ++ .phy_id_mask = MOTORCOMM_PHY_ID_MASK, ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) ) ++ .features = PHY_BASIC_FEATURES, ++ .flags = PHY_HAS_INTERRUPT, ++#endif ++ .config_aneg = yt8010_config_aneg, ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ .config_init = ytphy_config_init, ++#else ++ .config_init = genphy_config_init, ++#endif ++ .read_status = genphy_read_status, ++ }, { ++ .phy_id = PHY_ID_YT8510, ++ .name = "YT8510 100/10Mb Ethernet", ++ .phy_id_mask = MOTORCOMM_PHY_ID_MASK, ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) ) ++ .features = PHY_BASIC_FEATURES, ++ .flags = PHY_HAS_INTERRUPT, ++#endif ++ .config_aneg = genphy_config_aneg, ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ .config_init = ytphy_config_init, ++#else ++ .config_init = genphy_config_init, ++#endif ++ .read_status = genphy_read_status, ++ }, { ++ .phy_id = PHY_ID_YT8511, + .name = "YT8511 Gigabit Ethernet", ++ .phy_id_mask = MOTORCOMM_PHY_ID_MASK, ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) ) ++ .features = PHY_GBIT_FEATURES, ++ .flags = PHY_HAS_INTERRUPT, ++#endif ++ .config_aneg = genphy_config_aneg, ++#if GMAC_CLOCK_INPUT_NEEDED + .config_init = yt8511_config_init, ++#else ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ .config_init = ytphy_config_init, ++#else ++ .config_init = genphy_config_init, ++#endif ++#endif ++ .read_status = genphy_read_status, + .suspend = genphy_suspend, + .resume = genphy_resume, +- .read_page = yt8511_read_page, +- .write_page = yt8511_write_page, +- }, ++ }, { ++ .phy_id = PHY_ID_YT8512, ++ .name = "YT8512 Ethernet", ++ .phy_id_mask = MOTORCOMM_PHY_ID_MASK, ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) ) ++ .features = PHY_BASIC_FEATURES, ++ .flags = PHY_HAS_INTERRUPT, ++#endif ++ .config_aneg = genphy_config_aneg, ++ .config_init = yt8512_config_init, ++ .read_status = yt8512_read_status, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ }, { ++ .phy_id = PHY_ID_YT8512B, ++ .name = "YT8512B Ethernet", ++ .phy_id_mask = MOTORCOMM_PHY_ID_MASK, ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) ) ++ .features = PHY_BASIC_FEATURES, ++ .flags = PHY_HAS_INTERRUPT, ++#endif ++ .config_aneg = genphy_config_aneg, ++ .config_init = yt8512_config_init, ++ .read_status = yt8512_read_status, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ }, { ++ .phy_id = PHY_ID_YT8521, ++ .name = "YT8521 Ethernet", ++ .phy_id_mask = MOTORCOMM_PHY_ID_MASK, ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) ) ++ .features = PHY_BASIC_FEATURES | PHY_GBIT_FEATURES, ++#endif ++ .flags = PHY_POLL, ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++#else ++ .soft_reset = yt8521_soft_reset, ++#endif ++ .config_aneg = genphy_config_aneg, ++#if ( LINUX_VERSION_CODE > KERNEL_VERSION(3,11,0) ) ++ .aneg_done = yt8521_aneg_done, ++#endif ++ .config_init = yt8521_config_init, ++ .read_status = yt8521_read_status, ++ .suspend = yt8521_suspend, ++ .resume = yt8521_resume, ++#if (YTPHY_ENABLE_WOL) ++ .get_wol = &ytphy_get_wol, ++ .set_wol = &ytphy_set_wol, ++#endif ++ },{ ++ /* same as 8521 */ ++ .phy_id = PHY_ID_YT8531S, ++ .name = "YT8531S Ethernet", ++ .phy_id_mask = MOTORCOMM_PHY_ID_MASK, ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) ) ++ .features = PHY_BASIC_FEATURES | PHY_GBIT_FEATURES, ++#endif ++ .flags = PHY_POLL, ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++#else ++ .soft_reset = yt8521_soft_reset, ++#endif ++ .config_aneg = genphy_config_aneg, ++#if ( LINUX_VERSION_CODE > KERNEL_VERSION(3,11,0) ) ++ .aneg_done = yt8521_aneg_done, ++#endif ++ .config_init = yt8521_config_init, ++ .read_status = yt8521_read_status, ++ .suspend = yt8521_suspend, ++ .resume = yt8521_resume, ++#if (YTPHY_ENABLE_WOL) ++ .get_wol = &ytphy_get_wol, ++ .set_wol = &ytphy_set_wol, ++#endif ++ }, { ++ /* same as 8511 */ ++ .phy_id = PHY_ID_YT8531, ++ .name = "YT8531 Gigabit Ethernet", ++ .phy_id_mask = MOTORCOMM_PHY_ID_MASK, ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) ) ++ .features = PHY_BASIC_FEATURES | PHY_GBIT_FEATURES, ++ .flags = PHY_HAS_INTERRUPT, ++#endif ++ .config_aneg = genphy_config_aneg, ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++ .config_init = ytphy_config_init, ++#else ++ .config_init = genphy_config_init, ++#endif ++ .read_status = genphy_read_status, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++#if (YTPHY_ENABLE_WOL) ++ .get_wol = &ytphy_get_wol, ++ .set_wol = &ytphy_set_wol, ++#endif ++ }, { ++ .phy_id = PHY_ID_YT8618, ++ .name = "YT8618 Ethernet", ++ .phy_id_mask = MOTORCOMM_MPHY_ID_MASK, ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) ) ++ .features = PHY_BASIC_FEATURES | PHY_GBIT_FEATURES, ++#endif ++ .flags = PHY_POLL, ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++#else ++ .soft_reset = yt8618_soft_reset, ++#endif ++ .config_aneg = genphy_config_aneg, ++#if ( LINUX_VERSION_CODE > KERNEL_VERSION(3,11,0) ) ++ .aneg_done = yt8618_aneg_done, ++#endif ++ .config_init = yt8618_config_init, ++ .read_status = yt8618_read_status, ++ .suspend = yt8618_suspend, ++ .resume = yt8618_resume, ++ }, { ++ .phy_id = PHY_ID_YT8614, ++ .name = "YT8614 Ethernet", ++ .phy_id_mask = MOTORCOMM_MPHY_ID_MASK_8614, ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(5,4,0) ) ++ .features = PHY_BASIC_FEATURES | PHY_GBIT_FEATURES, ++#endif ++ .flags = PHY_POLL, ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++#else ++ .soft_reset = yt8614_soft_reset, ++#endif ++ .config_aneg = genphy_config_aneg, ++#if ( LINUX_VERSION_CODE > KERNEL_VERSION(3,11,0) ) ++ .aneg_done = yt8614_aneg_done, ++#endif ++ .config_init = yt8614_config_init, ++ .read_status = yt8614_read_status, ++ .suspend = yt8614_suspend, ++ .resume = yt8614_resume, ++ }, + }; + +-module_phy_driver(motorcomm_phy_drvs); ++#if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0) ) ++static int ytphy_drivers_register(struct phy_driver* phy_drvs, int size) ++{ ++ int i, j; ++ int ret; ++ ++ for (i = 0; i < size; i++) { ++ ret = phy_driver_register(&phy_drvs[i]); ++ if (ret) ++ goto err; ++ } ++ ++ return 0; ++ ++err: ++ for (j = 0; j < i; j++) ++ phy_driver_unregister(&phy_drvs[j]); ++ ++ return ret; ++} ++ ++static void ytphy_drivers_unregister(struct phy_driver* phy_drvs, int size) ++{ ++ int i; ++ ++ for (i = 0; i < size; i++) { ++ phy_driver_unregister(&phy_drvs[i]); ++ } ++} ++ ++static int __init ytphy_init(void) ++{ ++ printk("motorcomm phy register\n"); ++ return ytphy_drivers_register(ytphy_drvs, ARRAY_SIZE(ytphy_drvs)); ++} ++ ++static void __exit ytphy_exit(void) ++{ ++ printk("motorcomm phy unregister\n"); ++ ytphy_drivers_unregister(ytphy_drvs, ARRAY_SIZE(ytphy_drvs)); ++} ++ ++module_init(ytphy_init); ++module_exit(ytphy_exit); ++#else ++/* for linux 4.x */ ++module_phy_driver(ytphy_drvs); ++#endif + + MODULE_DESCRIPTION("Motorcomm PHY driver"); +-MODULE_AUTHOR("Peter Geis"); ++MODULE_AUTHOR("Leilei Zhao"); + MODULE_LICENSE("GPL"); + +-static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = { +- { PHY_ID_MATCH_EXACT(PHY_ID_YT8511) }, +- { /* sentinal */ } ++static struct mdio_device_id __maybe_unused motorcomm_tbl[] = { ++ { PHY_ID_YT8010, MOTORCOMM_PHY_ID_MASK }, ++ { PHY_ID_YT8510, MOTORCOMM_PHY_ID_MASK }, ++ { PHY_ID_YT8511, MOTORCOMM_PHY_ID_MASK }, ++ { PHY_ID_YT8512, MOTORCOMM_PHY_ID_MASK }, ++ { PHY_ID_YT8512B, MOTORCOMM_PHY_ID_MASK }, ++ { PHY_ID_YT8521, MOTORCOMM_PHY_ID_MASK }, ++ { PHY_ID_YT8531S, MOTORCOMM_PHY_ID_8531_MASK }, ++ { PHY_ID_YT8531, MOTORCOMM_PHY_ID_8531_MASK }, ++ { PHY_ID_YT8618, MOTORCOMM_MPHY_ID_MASK }, ++ { PHY_ID_YT8614, MOTORCOMM_MPHY_ID_MASK_8614 }, ++ { } + }; + + MODULE_DEVICE_TABLE(mdio, motorcomm_tbl); ++ ++ +--- /dev/null ++++ b/drivers/net/phy/yt8614-phy.h +@@ -0,0 +1,491 @@ ++#ifndef _PHY_H_ ++#define _PHY_H_ ++ ++ ++/* configuration for driver */ ++ ++#define YT8614_MAX_LPORT_ID 3 ++ ++#define YT8614_PHY_MODE_FIBER 1 //fiber mode only ++#define YT8614_PHY_MODE_UTP 2 //utp mode only ++#define YT8614_PHY_MODE_POLL 3 //fiber and utp, poll mode ++ ++/* please make choice according to system design ++ * for Fiber only system, please define YT8614_PHY_MODE_CURR 1 ++ * for UTP only system, please define YT8614_PHY_MODE_CURR 2 ++ * for combo system, please define YT8614_PHY_MODE_CURR 3 ++ */ ++#define YT8614_PHY_MODE_CURR 3 ++ ++ ++ ++/* pls dont modify below lines */ ++ ++#define PHY_ID_YT8614 0x4F51E899 //serdes ++#define MOTORCOMM_MPHY_ID_MASK_8614 0xffffffff ++ ++#ifndef BOOL ++#define BOOL unsigned int ++#endif ++ ++#ifndef FALSE ++#define FALSE 0 ++#endif ++ ++#ifndef TRUE ++#define TRUE 1 ++#endif ++ ++#ifndef SPEED_1000M ++#define SPEED_1000M 2 ++#endif ++#ifndef SPEED_100M ++#define SPEED_100M 1 ++#endif ++#ifndef SPEED_10M ++#define SPEED_10M 0 ++#endif ++ ++#ifndef SPEED_UNKNOWN ++#define SPEED_UNKNOWN 0xffff ++#endif ++ ++#ifndef DUPLEX_FULL ++#define DUPLEX_FULL 1 ++#endif ++#ifndef DUPLEX_HALF ++#define DUPLEX_HALF 0 ++#endif ++ ++#ifndef BIT ++#define BIT(n) (0x1<<(n)) ++#endif ++#ifndef s32 ++typedef int s32; ++typedef unsigned int u32; ++typedef unsigned short u16; ++typedef unsigned char u8; ++#endif ++ ++#ifndef REG_PHY_SPEC_STATUS ++#define REG_PHY_SPEC_STATUS 0x11 ++#define REG_DEBUG_ADDR_OFFSET 0x1e ++#define REG_DEBUG_DATA 0x1f ++#endif ++ ++/**********YT8614************************************************/ ++ ++#define YT8614_SMI_SEL_PHY 0x0 ++#define YT8614_SMI_SEL_SDS_QSGMII 0x02 ++#define YT8614_SMI_SEL_SDS_SGMII 0x03 ++ ++/* yt8614 register type */ ++#define YT8614_TYPE_COMMON 0x01 ++#define YT8614_TYPE_UTP_MII 0x02 ++#define YT8614_TYPE_UTP_EXT 0x03 ++#define YT8614_TYPE_LDS_MII 0x04 ++#define YT8614_TYPE_UTP_MMD 0x05 ++#define YT8614_TYPE_SDS_QSGMII_MII 0x06 ++#define YT8614_TYPE_SDS_SGMII_MII 0x07 ++#define YT8614_TYPE_SDS_QSGMII_EXT 0x08 ++#define YT8614_TYPE_SDS_SGMII_EXT 0x09 ++ ++/* YT8614 extended common register */ ++#define YT8614_REG_COM_SMI_MUX 0xA000 ++#define YT8614_REG_COM_SLED_CFG0 0xA001 ++#define YT8614_REG_COM_PHY_ID 0xA002 ++#define YT8614_REG_COM_CHIP_VER 0xA003 ++#define YT8614_REG_COM_SLED_CFG 0xA004 ++#define YT8614_REG_COM_MODE_CHG_RESET 0xA005 ++#define YT8614_REG_COM_SYNCE0_CFG 0xA006 ++#define YT8614_REG_COM_CHIP_MODE 0xA007 ++ ++#define YT8614_REG_COM_HIDE_SPEED 0xA009 ++ ++#define YT8614_REG_COM_SYNCE1_CFG 0xA00E ++ ++#define YT8614_REG_COM_HIDE_FIBER_MODE 0xA019 ++ ++ ++#define YT8614_REG_COM_HIDE_SEL1 0xA054 ++#define YT8614_REG_COM_HIDE_LED_CFG2 0xB8 ++#define YT8614_REG_COM_HIDE_LED_CFG3 0xB9 ++#define YT8614_REG_COM_HIDE_LED_CFG5 0xBB ++ ++#define YT8614_REG_COM_HIDE_LED_CFG4 0xBA //not used currently ++ ++#if 0 ++#define YT8614_REG_COM_HIDE_LED12_CFG 0xA060 //not used currently ++#define YT8614_REG_COM_HIDE_LED13_CFG 0xA061 ++#define YT8614_REG_COM_HIDE_LED14_CFG 0xA062 ++#define YT8614_REG_COM_HIDE_LED15_CFG 0xA063 ++#define YT8614_REG_COM_HIDE_LED16_CFG 0xA064 ++#define YT8614_REG_COM_HIDE_LED17_CFG 0xA065 ++#define YT8614_REG_COM_HIDE_LED18_CFG 0xA066 ++#define YT8614_REG_COM_HIDE_LED19_CFG 0xA067 ++#define YT8614_REG_COM_HIDE_LED20_CFG 0xA068 ++#define YT8614_REG_COM_HIDE_LED21_CFG 0xA069 ++#define YT8614_REG_COM_HIDE_LED22_CFG 0xA06A ++#define YT8614_REG_COM_HIDE_LED23_CFG 0xA06B ++#define YT8614_REG_COM_HIDE_LED24_CFG 0xA06C ++#define YT8614_REG_COM_HIDE_LED25_CFG 0xA06D ++#define YT8614_REG_COM_HIDE_LED26_CFG 0xA06E ++#define YT8614_REG_COM_HIDE_LED27_CFG 0xA06F ++#endif ++ ++#define YT8614_REG_COM_HIDE_LED28_CFG 0xA070 ++#define YT8614_REG_COM_HIDE_LED29_CFG 0xA071 ++#define YT8614_REG_COM_HIDE_LED30_CFG 0xA072 ++#define YT8614_REG_COM_HIDE_LED31_CFG 0xA073 ++#define YT8614_REG_COM_HIDE_LED32_CFG 0xA074 ++#define YT8614_REG_COM_HIDE_LED33_CFG 0xA075 ++#define YT8614_REG_COM_HIDE_LED34_CFG 0xA076 ++#define YT8614_REG_COM_HIDE_LED35_CFG 0xA077 ++ ++#define YT8614_REG_COM_PKG_CFG0 0xA0A0 ++#define YT8614_REG_COM_PKG_CFG1 0xA0A1 ++#define YT8614_REG_COM_PKG_CFG2 0xA0A2 ++#define YT8614_REG_COM_PKG_RX_VALID0 0xA0A3 ++#define YT8614_REG_COM_PKG_RX_VALID1 0xA0A4 ++#define YT8614_REG_COM_PKG_RX_OS0 0xA0A5 ++#define YT8614_REG_COM_PKG_RX_OS1 0xA0A6 ++#define YT8614_REG_COM_PKG_RX_US0 0xA0A7 ++#define YT8614_REG_COM_PKG_RX_US1 0xA0A8 ++#define YT8614_REG_COM_PKG_RX_ERR 0xA0A9 ++#define YT8614_REG_COM_PKG_RX_OS_BAD 0xA0AA ++#define YT8614_REG_COM_PKG_RX_FRAG 0xA0AB ++#define YT8614_REG_COM_PKG_RX_NOSFD 0xA0AC ++#define YT8614_REG_COM_PKG_TX_VALID0 0xA0AD ++#define YT8614_REG_COM_PKG_TX_VALID1 0xA0AE ++#define YT8614_REG_COM_PKG_TX_OS0 0xA0AF ++ ++#define YT8614_REG_COM_PKG_TX_OS1 0xA0B0 ++#define YT8614_REG_COM_PKG_TX_US0 0xA0B1 ++#define YT8614_REG_COM_PKG_TX_US1 0xA0B2 ++#define YT8614_REG_COM_PKG_TX_ERR 0xA0B3 ++#define YT8614_REG_COM_PKG_TX_OS_BAD 0xA0B4 ++#define YT8614_REG_COM_PKG_TX_FRAG 0xA0B5 ++#define YT8614_REG_COM_PKG_TX_NOSFD 0xA0B6 ++#define YT8614_REG_COM_PKG_CFG3 0xA0B7 ++#define YT8614_REG_COM_PKG_AZ_CFG 0xA0B8 ++#define YT8614_REG_COM_PKG_DA_SA_CFG3 0xA0B9 ++ ++#define YT8614_REG_COM_MANU_HW_RESET 0xA0C0 ++ ++/* YT8614 UTP MII register: same as generic phy register definitions */ ++#define REG_MII_BMCR 0x00 /* Basic mode control register */ ++#define REG_MII_BMSR 0x01 /* Basic mode status register */ ++#define REG_MII_PHYSID1 0x02 /* PHYS ID 1 */ ++#define REG_MII_PHYSID2 0x03 /* PHYS ID 2 */ ++#define REG_MII_ADVERTISE 0x04 /* Advertisement control reg */ ++#define REG_MII_LPA 0x05 /* Link partner ability reg */ ++#define REG_MII_EXPANSION 0x06 /* Expansion register */ ++#define REG_MII_NEXT_PAGE 0x07 /* Next page register */ ++#define REG_MII_LPR_NEXT_PAGE 0x08 /* LPR next page register */ ++#define REG_MII_CTRL1000 0x09 /* 1000BASE-T control */ ++#define REG_MII_STAT1000 0x0A /* 1000BASE-T status */ ++ ++#define REG_MII_MMD_CTRL 0x0D /* MMD access control register */ ++#define REG_MII_MMD_DATA 0x0E /* MMD access data register */ ++ ++#define REG_MII_ESTATUS 0x0F /* Extended Status */ ++#define REG_MII_SPEC_CTRL 0x10 /* PHY specific func control */ ++#define REG_MII_SPEC_STATUS 0x11 /* PHY specific status */ ++#define REG_MII_INT_MASK 0x12 /* Interrupt mask register */ ++#define REG_MII_INT_STATUS 0x13 /* Interrupt status register */ ++#define REG_MII_DOWNG_CTRL 0x14 /* Speed auto downgrade control*/ ++#define REG_MII_RERRCOUNTER 0x15 /* Receive error counter */ ++ ++#define REG_MII_EXT_ADDR 0x1E /* Extended reg's address */ ++#define REG_MII_EXT_DATA 0x1F /* Extended reg's date */ ++ ++#ifndef MII_BMSR ++#define MII_BMSR REG_MII_BMSR ++#endif ++ ++#ifndef YT8614_SPEED_MODE_BIT ++#define YT8614_SPEED_MODE 0xc000 ++#define YT8614_DUPLEX 0x2000 ++#define YT8614_SPEED_MODE_BIT 14 ++#define YT8614_DUPLEX_BIT 13 ++#define YT8614_LINK_STATUS_BIT 10 ++ ++#endif ++ ++#define YT8614_REG_COM_HIDE_SPEED_CMB_PRI 0x2000 ++ ++/* YT8614 UTP MMD register */ ++#define YT8614_REG_UTP_MMD_CTRL1 0x00 /* PCS control 1 register */ ++#define YT8614_REG_UTP_MMD_STATUS1 0x01 /* PCS status 1 register */ ++#define YT8614_REG_UTP_MMD_EEE_CTRL 0x14 /* EEE control and capability */ ++#define YT8614_REG_UTP_MMD_EEE_WK_ERR_CNT 0x16 /* EEE wake error counter */ ++#define YT8614_REG_UTP_MMD_EEE_LOCAL_ABI 0x3C /* local device EEE ability */ ++#define YT8614_REG_UTP_MMD_EEE_LP_ABI 0x3D /* link partner EEE ability */ ++#define YT8614_REG_UTP_MMD_EEE_AUTONEG_RES 0x8000 /* autoneg result of EEE */ ++ ++/* YT8614 UTP EXT register */ ++#define YT8614_REG_UTP_EXT_LPBK 0x0A ++#define YT8614_REG_UTP_EXT_SLEEP_CTRL1 0x27 ++#define YT8614_REG_UTP_EXT_DEBUG_MON1 0x5A ++#define YT8614_REG_UTP_EXT_DEBUG_MON2 0x5B ++#define YT8614_REG_UTP_EXT_DEBUG_MON3 0x5C ++#define YT8614_REG_UTP_EXT_DEBUG_MON4 0x5D ++ ++/* YT8614 SDS(1.25G/5G) MII register: same as YT8521S */ ++#define REG_SDS_BMCR 0x00 /* Basic mode control register */ ++#define REG_SDS_BMSR 0x01 /* Basic mode status register */ ++#define REG_SDS_PHYSID1 0x02 /* PHYS ID 1 */ ++#define REG_SDS_PHYSID2 0x03 /* PHYS ID 2 */ ++#define REG_SDS_ADVERTISE 0x04 /* Advertisement control reg */ ++#define REG_SDS_LPA 0x05 /* Link partner ability reg */ ++#define REG_SDS_EXPANSION 0x06 /* Expansion register */ ++#define REG_SDS_NEXT_PAGE 0x07 /* Next page register */ ++#define REG_SDS_LPR_NEXT_PAGE 0x08 /* LPR next page register */ ++ ++#define REG_SDS_ESTATUS 0x0F /* Extended Status */ ++#define REG_SDS_SPEC_STATUS 0x11 /* SDS specific status */ ++ ++#define REG_SDS_100FX_CFG 0x14 /* 100fx cfg */ ++#define REG_SDS_RERRCOUNTER 0x15 /* Receive error counter */ ++#define REG_SDS_LINT_FAIL_CNT 0x16 /* Lint fail counter mon */ ++ ++/* YT8614 SDS(5G) EXT register */ ++#define YT8614_REG_QSGMII_EXT_ANA_DIG_CFG 0x02 /* sds analog digital interface cfg */ ++#define YT8614_REG_QSGMII_EXT_PRBS_CFG1 0x05 /* sds prbs cfg1 */ ++#define YT8614_REG_QSGMII_EXT_PRBS_CFG2_1 0x06 /* sds prbs cfg2 */ ++#define YT8614_REG_QSGMII_EXT_PRBS_CFG2_2 0x07 /* sds prbs cfg2 */ ++#define YT8614_REG_QSGMII_EXT_PRBS_MON1 0x08 /* sds prbs mon1 */ ++#define YT8614_REG_QSGMII_EXT_PRBS_MON2 0x09 /* sds prbs mon2 */ ++#define YT8614_REG_QSGMII_EXT_PRBS_MON3 0x0A /* sds prbs mon3 */ ++#define YT8614_REG_QSGMII_EXT_PRBS_MON4 0x0B /* sds prbs mon4 */ ++#define YT8614_REG_QSGMII_EXT_PRBS_MON5 0x0C /* sds prbs mon5 */ ++#define YT8614_REG_QSGMII_EXT_ANA_CFG2 0xA1 /* Analog cfg2 */ ++ ++/* YT8614 SDS(1.25G) EXT register */ ++#define YT8614_REG_SGMII_EXT_PRBS_CFG1 0x05 /* sds prbs cfg1 */ ++#define YT8614_REG_SGMII_EXT_PRBS_CFG2 0x06 /* sds prbs cfg2 */ ++#define YT8614_REG_SGMII_EXT_PRBS_MON1 0x08 /* sds prbs mon1 */ ++#define YT8614_REG_SGMII_EXT_PRBS_MON2 0x09 /* sds prbs mon2 */ ++#define YT8614_REG_SGMII_EXT_PRBS_MON3 0x0A /* sds prbs mon3 */ ++#define YT8614_REG_SGMII_EXT_PRBS_MON4 0x0B /* sds prbs mon4 */ ++#define YT8614_REG_SGMII_EXT_PRBS_MON5 0x0C /* sds prbs mon5 */ ++#define YT8614_REG_SGMII_EXT_ANA_CFG2 0xA1 /* Analog cfg2 */ ++#define YT8614_REG_SGMII_EXT_HIDE_AUTO_SEN 0xA5 /* Fiber auto sensing */ ++ ++//////////////////////////////////////////////////////////////////// ++#define YT8614_MMD_DEV_ADDR1 0x1 ++#define YT8614_MMD_DEV_ADDR3 0x3 ++#define YT8614_MMD_DEV_ADDR7 0x7 ++#define YT8614_MMD_DEV_ADDR_NONE 0xFF ++ ++/**********YT8521S************************************************/ ++/* Basic mode control register(0x00) */ ++#define BMCR_RESV 0x003f /* Unused... */ ++#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */ ++#define BMCR_CTST 0x0080 /* Collision test */ ++#define BMCR_FULLDPLX 0x0100 /* Full duplex */ ++#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */ ++#define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */ ++#define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */ ++#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */ ++#define BMCR_SPEED100 0x2000 /* Select 100Mbps */ ++#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */ ++#define BMCR_RESET 0x8000 /* Reset the DP83840 */ ++ ++/* Basic mode status register(0x01) */ ++#define BMSR_ERCAP 0x0001 /* Ext-reg capability */ ++#define BMSR_JCD 0x0002 /* Jabber detected */ ++#define BMSR_LSTATUS 0x0004 /* Link status */ ++#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */ ++#define BMSR_RFAULT 0x0010 /* Remote fault detected */ ++#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */ ++#define BMSR_RESV 0x00c0 /* Unused... */ ++#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */ ++#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */ ++#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */ ++#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */ ++#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */ ++#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */ ++#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */ ++#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */ ++ ++/* Advertisement control register(0x04) */ ++#define ADVERTISE_SLCT 0x001f /* Selector bits */ ++#define ADVERTISE_CSMA 0x0001 /* Only selector supported */ ++#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ ++#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */ ++#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ ++#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */ ++#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ ++#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */ ++#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ ++#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */ ++#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */ ++#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */ ++#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */ ++#define ADVERTISE_RESV 0x1000 /* Unused... */ ++#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */ ++#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */ ++#define ADVERTISE_NPAGE 0x8000 /* Next page bit */ ++ ++#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | ADVERTISE_CSMA) ++#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \ ++ ADVERTISE_100HALF | ADVERTISE_100FULL) ++ ++/* Link partner ability register(0x05) */ ++#define LPA_SLCT 0x001f /* Same as advertise selector */ ++#define LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */ ++#define LPA_1000XFULL 0x0020 /* Can do 1000BASE-X full-duplex */ ++#define LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */ ++#define LPA_1000XHALF 0x0040 /* Can do 1000BASE-X half-duplex */ ++#define LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */ ++#define LPA_1000XPAUSE 0x0080 /* Can do 1000BASE-X pause */ ++#define LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */ ++#define LPA_1000XPAUSE_ASYM 0x0100 /* Can do 1000BASE-X pause asym */ ++#define LPA_100BASE4 0x0200 /* Can do 100mbps 4k packets */ ++#define LPA_PAUSE_CAP 0x0400 /* Can pause */ ++#define LPA_PAUSE_ASYM 0x0800 /* Can pause asymetrically */ ++#define LPA_RESV 0x1000 /* Unused... */ ++#define LPA_RFAULT 0x2000 /* Link partner faulted */ ++#define LPA_LPACK 0x4000 /* Link partner acked us */ ++#define LPA_NPAGE 0x8000 /* Next page bit */ ++ ++/* 1000BASE-T Control register(0x09) */ ++#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */ ++#define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */ ++#define CTL1000_AS_MASTER 0x0800 ++#define CTL1000_ENABLE_MASTER 0x1000 ++ ++/* 1000BASE-T Status register(0x0A) */ ++#define LPA_1000LOCALRXOK 0x2000 /* Link partner local receiver status */ ++#define LPA_1000REMRXOK 0x1000 /* Link partner remote receiver status */ ++#define LPA_1000FULL 0x0800 /* Link partner 1000BASE-T full duplex */ ++#define LPA_1000HALF 0x0400 /* Link partner 1000BASE-T half duplex */ ++ ++/**********YT8614************************************************/ ++/* Basic mode control register(0x00) */ ++#define FIBER_BMCR_RESV 0x001f /* b[4:0] Unused... */ ++#define FIBER_BMCR_EN_UNIDIR 0x0020 /* b[5] Valid when bit 0.12 is zero and bit 0.8 is one */ ++#define FIBER_BMCR_SPEED1000 0x0040 /* b[6] MSB of Speed (1000) */ ++#define FIBER_BMCR_CTST 0x0080 /* b[7] Collision test */ ++#define FIBER_BMCR_DUPLEX_MODE 0x0100 /* b[8] Duplex mode */ ++#define FIBER_BMCR_ANRESTART 0x0200 /* b[9] Auto negotiation restart */ ++#define FIBER_BMCR_ISOLATE 0x0400 /* b[10] Isolate phy from RGMII/SGMII/FIBER */ ++#define FIBER_BMCR_PDOWN 0x0800 /* b[11] 1: Power down */ ++#define FIBER_BMCR_ANENABLE 0x1000 /* b[12] Enable auto negotiation */ ++#define FIBER_BMCR_SPEED100 0x2000 /* b[13] LSB of Speed (100) */ ++#define FIBER_BMCR_LOOPBACK 0x4000 /* b[14] Internal loopback control */ ++#define FIBER_BMCR_RESET 0x8000 /* b[15] PHY Software Reset(self-clear) */ ++ ++/* Sds specific status register(0x11) */ ++#define FIBER_SSR_ERCAP 0x0001 /* b[0] realtime syncstatus */ ++#define FIBER_SSR_XMIT 0x000E /* b[3:1] realtime transmit statemachine. ++ 001: Xmit Idle; ++ 010: Xmit Config; ++ 100: Xmit Data. */ ++#define FIBER_SSR_SER_MODE_CFG 0x0030 /* b[5:4] realtime serdes working mode. ++ 00: SG_MAC; ++ 01: SG_PHY; ++ 10: FIB_1000; ++ 11: FIB_100. */ ++#define FIBER_SSR_EN_FLOWCTRL_TX 0x0040 /* b[6] realtime en_flowctrl_tx */ ++#define FIBER_SSR_EN_FLOWCTRL_RX 0x0080 /* b[7] realtime en_flowctrl_rx */ ++#define FIBER_SSR_DUPLEX_ERROR 0x0100 /* b[8] realtime deplex error */ ++#define FIBER_SSR_RX_LPI_ACTIVE 0x0200 /* b[9] rx lpi is active */ ++#define FIBER_SSR_LSTATUS 0x0400 /* b[10] Link status real-time */ ++#define FIBER_SSR_PAUSE 0x1800 /* b[12:11] Pause to mac */ ++#define FIBER_SSR_DUPLEX 0x2000 /* b[13] This status bit is valid only when bit10 is 1. ++ 1: full duplex ++ 0: half duplex */ ++#define FIBER_SSR_SPEED_MODE 0xC000 /* b[15:14] These status bits are valid only when bit10 is 1. ++ 10---1000M ++ 01---100M */ ++ ++/* SLED cfg0 (ext 0xA001) */ ++#define FIBER_SLED_CFG0_EN_CTRL 0x00FF /* b[7:0] Control to enable the eight ports' SLED */ ++#define FIBER_SLED_CFG0_BIT_MASK 0x0700 /* b[10:8] 1: enable the pin output */ ++#define FIBER_SLED_CFG0_ACT_LOW 0x0800 /* b[11] control SLED's polarity. 1: active low; 0: active high */ ++#define FIBER_SLED_CFG0_MANU_ST 0x7000 /* b[14:12] SLEDs' manul status, corresponding to each port's 3 SLEDs */ ++#define FIBER_SLED_CFG0_MANU_EN 0x8000 /* b[15] to control serial LEDs status manually */ ++ ++/**********YT8614************************************************/ ++/* Fiber auto sensing(sgmii ext 0xA5) */ ++#define FIBER_AUTO_SEN_ENABLE 0x8000 /* b[15] Enable fiber auto sensing */ ++ ++/* Fiber force speed(common ext 0xA009) */ ++#define FIBER_FORCE_1000M 0x0001 /* b[0] 1:1000BX 0:100FX */ ++ ++#ifndef NULL ++#define NULL 0 ++#endif ++ ++/* errno */ ++enum ytphy_8614_errno_e ++{ ++ SYS_E_NONE, ++ SYS_E_PARAM, ++ SYS_E_MAX ++}; ++ ++/* errno */ ++enum ytphy_8614_combo_speed_e ++{ ++ YT8614_COMBO_FIBER_1000M, ++ YT8614_COMBO_FIBER_100M, ++ YT8614_COMBO_UTP_ONLY, ++ YT8614_COMBO_SPEED_MAX ++}; ++ ++/* definition for porting */ ++/* phy registers access */ ++typedef struct ++{ ++ u16 reg; /* the offset of the phy internal address */ ++ u16 val; /* the value of the register */ ++ u8 regType; /* register type */ ++} phy_data_s; ++ ++/* for porting use. ++ * pls over-write member function read/write for mdio access ++ */ ++typedef struct phy_info_str ++{ ++#if 0 ++ struct phy_device *phydev; ++ int mdio_base; ++#endif ++ unsigned int lport; ++ unsigned int bus_id; ++ unsigned int phy_addr; ++ ++ s32 (*read)(struct phy_info_str *info, phy_data_s *param); ++ s32 (*write)(struct phy_info_str *info, phy_data_s *param); ++}phy_info_s; ++ ++/* get phy access method */ ++s32 yt8614_read_reg(struct phy_info_str *info, phy_data_s *param); ++s32 yt8614_write_reg(struct phy_info_str *info, phy_data_s *param); ++s32 yt8614_phy_soft_reset(u32 lport); ++s32 yt8614_phy_init(u32 lport); ++s32 yt8614_fiber_enable(u32 lport, BOOL enable); ++s32 yt8614_utp_enable(u32 lport, BOOL enable); ++s32 yt8614_fiber_unidirection_set(u32 lport, int speed, BOOL enable); ++s32 yt8614_fiber_autosensing_set(u32 lport, BOOL enable); ++s32 yt8614_fiber_speed_set(u32 lport, int fiber_speed); ++s32 yt8614_qsgmii_autoneg_set(u32 lport, BOOL enable); ++s32 yt8614_sgmii_autoneg_set(u32 lport, BOOL enable); ++s32 yt8614_qsgmii_sgmii_link_status_get(u32 lport, BOOL *enable, BOOL if_qsgmii); ++int yt8614_combo_media_priority_set (u32 lport, int fiber); ++int yt8614_combo_media_priority_get (u32 lport, int *fiber); ++s32 yt8614_utp_autoneg_set(u32 lport, BOOL enable); ++s32 yt8614_utp_autoneg_get(u32 lport, BOOL *enable); ++s32 yt8614_utp_autoneg_ability_set(u32 lport, unsigned int cap_mask); ++s32 yt8614_utp_autoneg_ability_get(u32 lport, unsigned int *cap_mask); ++s32 yt8614_utp_force_duplex_set(u32 lport, BOOL full); ++s32 yt8614_utp_force_duplex_get(u32 lport, BOOL *full); ++s32 yt8614_utp_force_speed_set(u32 lport, unsigned int speed); ++s32 yt8614_utp_force_speed_get(u32 lport, unsigned int *speed); ++int yt8614_autoneg_done_get (u32 lport, int speed, int *aneg); ++int yt8614_media_status_get(u32 lport, int* speed, int* duplex, int* ret_link, int *media); ++ ++#endif +--- /dev/null ++++ b/include/linux/motorcomm_phy.h +@@ -0,0 +1,119 @@ ++/* ++ * include/linux/motorcomm_phy.h ++ * ++ * Motorcomm PHY IDs ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ */ ++ ++#ifndef _MOTORCOMM_PHY_H ++#define _MOTORCOMM_PHY_H ++ ++#define MOTORCOMM_PHY_ID_MASK 0x00000fff ++#define MOTORCOMM_PHY_ID_8531_MASK 0xffffffff ++#define MOTORCOMM_MPHY_ID_MASK 0x0000ffff ++ ++#define PHY_ID_YT8010 0x00000309 ++#define PHY_ID_YT8510 0x00000109 ++#define PHY_ID_YT8511 0x0000010a ++#define PHY_ID_YT8512 0x00000118 ++#define PHY_ID_YT8512B 0x00000128 ++#define PHY_ID_YT8521 0x0000011a ++#define PHY_ID_YT8531S 0x4f51e91a ++#define PHY_ID_YT8531 0x4f51e91b ++//#define PHY_ID_YT8614 0x0000e899 ++#define PHY_ID_YT8618 0x0000e889 ++ ++#define REG_PHY_SPEC_STATUS 0x11 ++#define REG_DEBUG_ADDR_OFFSET 0x1e ++#define REG_DEBUG_DATA 0x1f ++ ++#define YT8512_EXTREG_AFE_PLL 0x50 ++#define YT8512_EXTREG_EXTEND_COMBO 0x4000 ++#define YT8512_EXTREG_LED0 0x40c0 ++#define YT8512_EXTREG_LED1 0x40c3 ++ ++#define YT8512_EXTREG_SLEEP_CONTROL1 0x2027 ++ ++#define YT_SOFTWARE_RESET 0x8000 ++ ++#define YT8512_CONFIG_PLL_REFCLK_SEL_EN 0x0040 ++#define YT8512_CONTROL1_RMII_EN 0x0001 ++#define YT8512_LED0_ACT_BLK_IND 0x1000 ++#define YT8512_LED0_DIS_LED_AN_TRY 0x0001 ++#define YT8512_LED0_BT_BLK_EN 0x0002 ++#define YT8512_LED0_HT_BLK_EN 0x0004 ++#define YT8512_LED0_COL_BLK_EN 0x0008 ++#define YT8512_LED0_BT_ON_EN 0x0010 ++#define YT8512_LED1_BT_ON_EN 0x0010 ++#define YT8512_LED1_TXACT_BLK_EN 0x0100 ++#define YT8512_LED1_RXACT_BLK_EN 0x0200 ++#define YT8512_SPEED_MODE 0xc000 ++#define YT8512_DUPLEX 0x2000 ++ ++#define YT8512_SPEED_MODE_BIT 14 ++#define YT8512_DUPLEX_BIT 13 ++#define YT8512_EN_SLEEP_SW_BIT 15 ++ ++#define YT8521_EXTREG_SLEEP_CONTROL1 0x27 ++#define YT8521_EN_SLEEP_SW_BIT 15 ++ ++#define YT8521_SPEED_MODE 0xc000 ++#define YT8521_DUPLEX 0x2000 ++#define YT8521_SPEED_MODE_BIT 14 ++#define YT8521_DUPLEX_BIT 13 ++#define YT8521_LINK_STATUS_BIT 10 ++ ++/* based on yt8521 wol config register */ ++#define YTPHY_UTP_INTR_REG 0x12 ++/* WOL Event Interrupt Enable */ ++#define YTPHY_WOL_INTR BIT(6) ++ ++/* Magic Packet MAC address registers */ ++#define YTPHY_MAGIC_PACKET_MAC_ADDR2 0xa007 ++#define YTPHY_MAGIC_PACKET_MAC_ADDR1 0xa008 ++#define YTPHY_MAGIC_PACKET_MAC_ADDR0 0xa009 ++ ++#define YTPHY_WOL_CFG_REG 0xa00a ++#define YTPHY_WOL_CFG_TYPE BIT(0) /* WOL TYPE */ ++#define YTPHY_WOL_CFG_EN BIT(3) /* WOL Enable */ ++#define YTPHY_WOL_CFG_INTR_SEL BIT(6) /* WOL Event Interrupt Enable */ ++#define YTPHY_WOL_CFG_WIDTH1 BIT(1) /* WOL Pulse Width */ ++#define YTPHY_WOL_CFG_WIDTH2 BIT(2) ++ ++#define YTPHY_REG_SPACE_UTP 0 ++#define YTPHY_REG_SPACE_FIBER 2 ++ ++enum ytphy_wol_type_e ++{ ++ YTPHY_WOL_TYPE_LEVEL, ++ YTPHY_WOL_TYPE_PULSE, ++ YTPHY_WOL_TYPE_MAX ++}; ++typedef enum ytphy_wol_type_e ytphy_wol_type_t; ++ ++enum ytphy_wol_width_e ++{ ++ YTPHY_WOL_WIDTH_84MS, ++ YTPHY_WOL_WIDTH_168MS, ++ YTPHY_WOL_WIDTH_336MS, ++ YTPHY_WOL_WIDTH_672MS, ++ YTPHY_WOL_WIDTH_MAX ++}; ++typedef enum ytphy_wol_width_e ytphy_wol_width_t; ++ ++struct ytphy_wol_cfg_s ++{ ++ int enable; ++ int type; ++ int width; ++}; ++typedef struct ytphy_wol_cfg_s ytphy_wol_cfg_t; ++ ++#endif /* _MOTORCOMM_PHY_H */ ++ ++ diff --git a/target/linux/rockchip/patches-5.19/0057-arm64-dts-rockchip-add-hardware-random-number-genera.patch b/target/linux/rockchip/patches-5.19/0057-arm64-dts-rockchip-add-hardware-random-number-genera.patch new file mode 100644 index 000000000..266b8b28d --- /dev/null +++ b/target/linux/rockchip/patches-5.19/0057-arm64-dts-rockchip-add-hardware-random-number-genera.patch @@ -0,0 +1,50 @@ +From e5b5361651940ff5c0c1784dfd0130abec7ab535 Mon Sep 17 00:00:00 2001 +From: wevsty +Date: Mon, 24 Aug 2020 02:27:11 +0800 +Subject: [PATCH] arm64: dts: rockchip: add hardware random number generator + for RK3328 and RK3399 + +Adding Hardware Random Number Generator Resources to the RK3328 and RK3399. + +Signed-off-by: wevsty +--- + +--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi +@@ -279,6 +279,17 @@ + status = "disabled"; + }; + ++ rng: rng@ff060000 { ++ compatible = "rockchip,cryptov1-rng"; ++ reg = <0x0 0xff060000 0x0 0x4000>; ++ ++ clocks = <&cru SCLK_CRYPTO>, <&cru HCLK_CRYPTO_SLV>; ++ clock-names = "clk_crypto", "hclk_crypto"; ++ assigned-clocks = <&cru SCLK_CRYPTO>, <&cru HCLK_CRYPTO_SLV>; ++ assigned-clock-rates = <150000000>, <100000000>; ++ status = "disabled"; ++ }; ++ + grf: syscon@ff100000 { + compatible = "rockchip,rk3328-grf", "syscon", "simple-mfd"; + reg = <0x0 0xff100000 0x0 0x1000>; +--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +@@ -2017,6 +2017,16 @@ + }; + }; + ++ rng: rng@ff8b8000 { ++ compatible = "rockchip,cryptov1-rng"; ++ reg = <0x0 0xff8b8000 0x0 0x1000>; ++ clocks = <&cru SCLK_CRYPTO1>, <&cru HCLK_S_CRYPTO1>; ++ clock-names = "clk_crypto", "hclk_crypto"; ++ assigned-clocks = <&cru SCLK_CRYPTO1>, <&cru HCLK_S_CRYPTO1>; ++ assigned-clock-rates = <150000000>, <100000000>; ++ status = "okay"; ++ }; ++ + gpu: gpu@ff9a0000 { + compatible = "rockchip,rk3399-mali", "arm,mali-t860"; + reg = <0x0 0xff9a0000 0x0 0x10000>; diff --git a/target/linux/rockchip/patches-5.19/0058-PM-devfreq-rockchip-add-devfreq-driver-for-rk3328-dmc.patch b/target/linux/rockchip/patches-5.19/0058-PM-devfreq-rockchip-add-devfreq-driver-for-rk3328-dmc.patch new file mode 100644 index 000000000..643c994f2 --- /dev/null +++ b/target/linux/rockchip/patches-5.19/0058-PM-devfreq-rockchip-add-devfreq-driver-for-rk3328-dmc.patch @@ -0,0 +1,44 @@ +From fcd9629c05f373771e85920e1c1d0ab252617878 Mon Sep 17 00:00:00 2001 +From: hmz007 +Date: Tue, 19 Nov 2019 13:53:25 +0800 +Subject: [PATCH] PM / devfreq: rockchip: add devfreq driver for rk3328 dmc + +Signed-off-by: hmz007 +--- + drivers/devfreq/Kconfig | 18 +- + drivers/devfreq/Makefile | 1 + + drivers/devfreq/rk3328_dmc.c | 846 +++++++++++++++++++++++++++++++++++ + 3 files changed, 862 insertions(+), 3 deletions(-) + create mode 100644 drivers/devfreq/rk3328_dmc.c + +--- a/drivers/devfreq/Kconfig ++++ b/drivers/devfreq/Kconfig +@@ -120,6 +120,18 @@ config ARM_TEGRA_DEVFREQ + It reads ACTMON counters of memory controllers and adjusts the + operating frequencies and voltages with OPP support. + ++config ARM_RK3328_DMC_DEVFREQ ++ tristate "ARM RK3328 DMC DEVFREQ Driver" ++ depends on ARCH_ROCKCHIP ++ select DEVFREQ_EVENT_ROCKCHIP_DFI ++ select DEVFREQ_GOV_SIMPLE_ONDEMAND ++ select PM_DEVFREQ_EVENT ++ select PM_OPP ++ help ++ This adds the DEVFREQ driver for the RK3328 DMC(Dynamic Memory Controller). ++ It sets the frequency for the memory controller and reads the usage counts ++ from hardware. ++ + config ARM_RK3399_DMC_DEVFREQ + tristate "ARM RK3399 DMC DEVFREQ Driver" + depends on (ARCH_ROCKCHIP && HAVE_ARM_SMCCC) || \ +--- a/drivers/devfreq/Makefile ++++ b/drivers/devfreq/Makefile +@@ -11,6 +11,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE) += gov + obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o + obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ) += imx-bus.o + obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ) += imx8m-ddrc.o ++obj-$(CONFIG_ARM_RK3328_DMC_DEVFREQ) += rk3328_dmc.o + obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o + obj-$(CONFIG_ARM_SUN8I_A33_MBUS_DEVFREQ) += sun8i-a33-mbus.o + obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra30-devfreq.o diff --git a/target/linux/rockchip/patches-5.19/0059-clk-rockchip-support-setting-ddr-clock-via-SIP-Version-2-.patch b/target/linux/rockchip/patches-5.19/0059-clk-rockchip-support-setting-ddr-clock-via-SIP-Version-2-.patch new file mode 100644 index 000000000..0408a0a73 --- /dev/null +++ b/target/linux/rockchip/patches-5.19/0059-clk-rockchip-support-setting-ddr-clock-via-SIP-Version-2-.patch @@ -0,0 +1,210 @@ +From ce6d3614888e6358466f0e84e248177a6bca5258 Mon Sep 17 00:00:00 2001 +From: Tang Yun ping +Date: Thu, 4 May 2017 20:49:58 +0800 +Subject: [PATCH] clk: rockchip: support setting ddr clock via SIP Version 2 + APIs + +commit 764e893ee82321938fc6f4349e9e7caf06a04410 rockchip. + +Signed-off-by: Tang Yun ping +Signed-off-by: hmz007 +--- + drivers/clk/rockchip/clk-ddr.c | 130 ++++++++++++++++++++++++++++ + drivers/clk/rockchip/clk-rk3328.c | 7 +- + drivers/clk/rockchip/clk.h | 3 +- + include/soc/rockchip/rockchip_sip.h | 11 +++ + 4 files changed, 147 insertions(+), 4 deletions(-) + +--- a/drivers/clk/rockchip/clk-ddr.c ++++ b/drivers/clk/rockchip/clk-ddr.c +@@ -87,6 +87,133 @@ static const struct clk_ops rockchip_ddr + .get_parent = rockchip_ddrclk_get_parent, + }; + ++/* See v4.4/include/dt-bindings/display/rk_fb.h */ ++#define SCREEN_NULL 0 ++#define SCREEN_HDMI 6 ++ ++static inline int rk_drm_get_lcdc_type(void) ++{ ++ return SCREEN_NULL; ++} ++ ++struct share_params { ++ u32 hz; ++ u32 lcdc_type; ++ u32 vop; ++ u32 vop_dclk_mode; ++ u32 sr_idle_en; ++ u32 addr_mcu_el3; ++ /* ++ * 1: need to wait flag1 ++ * 0: never wait flag1 ++ */ ++ u32 wait_flag1; ++ /* ++ * 1: need to wait flag1 ++ * 0: never wait flag1 ++ */ ++ u32 wait_flag0; ++ u32 complt_hwirq; ++ /* if need, add parameter after */ ++}; ++ ++struct rockchip_ddrclk_data { ++ u32 inited_flag; ++ void __iomem *share_memory; ++}; ++ ++static struct rockchip_ddrclk_data ddr_data; ++ ++static void rockchip_ddrclk_data_init(void) ++{ ++ struct arm_smccc_res res; ++ ++ arm_smccc_smc(ROCKCHIP_SIP_SHARE_MEM, ++ 1, SHARE_PAGE_TYPE_DDR, 0, ++ 0, 0, 0, 0, &res); ++ ++ if (!res.a0) { ++ ddr_data.share_memory = (void __iomem *)ioremap(res.a1, 1<<12); ++ ddr_data.inited_flag = 1; ++ } ++} ++ ++static int rockchip_ddrclk_sip_set_rate_v2(struct clk_hw *hw, ++ unsigned long drate, ++ unsigned long prate) ++{ ++ struct share_params *p; ++ struct arm_smccc_res res; ++ ++ if (!ddr_data.inited_flag) ++ rockchip_ddrclk_data_init(); ++ ++ p = (struct share_params *)ddr_data.share_memory; ++ ++ p->hz = drate; ++ p->lcdc_type = rk_drm_get_lcdc_type(); ++ p->wait_flag1 = 1; ++ p->wait_flag0 = 1; ++ ++ arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, ++ SHARE_PAGE_TYPE_DDR, 0, ++ ROCKCHIP_SIP_CONFIG_DRAM_SET_RATE, ++ 0, 0, 0, 0, &res); ++ ++ if ((int)res.a1 == -6) { ++ pr_err("%s: timeout, drate = %lumhz\n", __func__, drate/1000000); ++ /* TODO: rockchip_dmcfreq_wait_complete(); */ ++ } ++ ++ return res.a0; ++} ++ ++static unsigned long rockchip_ddrclk_sip_recalc_rate_v2 ++ (struct clk_hw *hw, unsigned long parent_rate) ++{ ++ struct arm_smccc_res res; ++ ++ arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, ++ SHARE_PAGE_TYPE_DDR, 0, ++ ROCKCHIP_SIP_CONFIG_DRAM_GET_RATE, ++ 0, 0, 0, 0, &res); ++ if (!res.a0) ++ return res.a1; ++ else ++ return 0; ++} ++ ++static long rockchip_ddrclk_sip_round_rate_v2(struct clk_hw *hw, ++ unsigned long rate, ++ unsigned long *prate) ++{ ++ struct share_params *p; ++ struct arm_smccc_res res; ++ ++ if (!ddr_data.inited_flag) ++ rockchip_ddrclk_data_init(); ++ ++ p = (struct share_params *)ddr_data.share_memory; ++ ++ p->hz = rate; ++ ++ arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, ++ SHARE_PAGE_TYPE_DDR, 0, ++ ROCKCHIP_SIP_CONFIG_DRAM_ROUND_RATE, ++ 0, 0, 0, 0, &res); ++ if (!res.a0) ++ return res.a1; ++ else ++ return 0; ++} ++ ++static const struct clk_ops rockchip_ddrclk_sip_ops_v2 = { ++ .recalc_rate = rockchip_ddrclk_sip_recalc_rate_v2, ++ .set_rate = rockchip_ddrclk_sip_set_rate_v2, ++ .round_rate = rockchip_ddrclk_sip_round_rate_v2, ++ .get_parent = rockchip_ddrclk_get_parent, ++}; ++ + struct clk *rockchip_clk_register_ddrclk(const char *name, int flags, + const char *const *parent_names, + u8 num_parents, int mux_offset, +@@ -114,6 +241,9 @@ struct clk *rockchip_clk_register_ddrclk + case ROCKCHIP_DDRCLK_SIP: + init.ops = &rockchip_ddrclk_sip_ops; + break; ++ case ROCKCHIP_DDRCLK_SIP_V2: ++ init.ops = &rockchip_ddrclk_sip_ops_v2; ++ break; + default: + pr_err("%s: unsupported ddrclk type %d\n", __func__, ddr_flag); + kfree(ddrclk); +--- a/drivers/clk/rockchip/clk-rk3328.c ++++ b/drivers/clk/rockchip/clk-rk3328.c +@@ -315,9 +315,10 @@ static struct rockchip_clk_branch rk3328 + RK3328_CLKGATE_CON(14), 1, GFLAGS), + + /* PD_DDR */ +- COMPOSITE(0, "clk_ddr", mux_ddrphy_p, CLK_IGNORE_UNUSED, +- RK3328_CLKSEL_CON(3), 8, 2, MFLAGS, 0, 3, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, +- RK3328_CLKGATE_CON(0), 4, GFLAGS), ++ COMPOSITE_DDRCLK(SCLK_DDRCLK, "sclk_ddrc", mux_ddrphy_p, 0, ++ RK3328_CLKSEL_CON(3), 8, 2, 0, 3, ++ ROCKCHIP_DDRCLK_SIP_V2), ++ + GATE(0, "clk_ddrmsch", "clk_ddr", CLK_IGNORE_UNUSED, + RK3328_CLKGATE_CON(18), 6, GFLAGS), + GATE(0, "clk_ddrupctl", "clk_ddr", CLK_IGNORE_UNUSED, +--- a/drivers/clk/rockchip/clk.h ++++ b/drivers/clk/rockchip/clk.h +@@ -399,7 +399,8 @@ struct clk *rockchip_clk_register_mmc(co + * DDRCLK flags, including method of setting the rate + * ROCKCHIP_DDRCLK_SIP: use SIP call to bl31 to change ddrclk rate. + */ +-#define ROCKCHIP_DDRCLK_SIP BIT(0) ++#define ROCKCHIP_DDRCLK_SIP 0x01 ++#define ROCKCHIP_DDRCLK_SIP_V2 0x03 + + struct clk *rockchip_clk_register_ddrclk(const char *name, int flags, + const char *const *parent_names, +--- a/include/soc/rockchip/rockchip_sip.h ++++ b/include/soc/rockchip/rockchip_sip.h +@@ -16,5 +16,16 @@ + #define ROCKCHIP_SIP_CONFIG_DRAM_CLR_IRQ 0x06 + #define ROCKCHIP_SIP_CONFIG_DRAM_SET_PARAM 0x07 + #define ROCKCHIP_SIP_CONFIG_DRAM_SET_ODT_PD 0x08 ++#define ROCKCHIP_SIP_CONFIG_DRAM_GET_VERSION 0x08 ++ ++#define ROCKCHIP_SIP_SHARE_MEM 0x82000009 ++ ++/* Share mem page types */ ++typedef enum { ++ SHARE_PAGE_TYPE_INVALID = 0, ++ SHARE_PAGE_TYPE_UARTDBG, ++ SHARE_PAGE_TYPE_DDR, ++ SHARE_PAGE_TYPE_MAX, ++} share_page_type_t; + + #endif diff --git a/target/linux/rockchip/patches-5.19/0060-PM-devfreq-rockchip-dfi-add-more-soc-support.patch b/target/linux/rockchip/patches-5.19/0060-PM-devfreq-rockchip-dfi-add-more-soc-support.patch new file mode 100644 index 000000000..283e4abd2 --- /dev/null +++ b/target/linux/rockchip/patches-5.19/0060-PM-devfreq-rockchip-dfi-add-more-soc-support.patch @@ -0,0 +1,662 @@ +From 4db93c6dad0c71750b86163df2fdb21c35f00d9a Mon Sep 17 00:00:00 2001 +From: hmz007 +Date: Tue, 19 Nov 2019 12:49:48 +0800 +Subject: [PATCH] PM / devfreq: rockchip-dfi: add more soc support + +Signed-off-by: hmz007 +--- + drivers/devfreq/event/rockchip-dfi.c | 554 ++++++++++++++++++++++++--- + 1 file changed, 505 insertions(+), 49 deletions(-) + +--- a/drivers/devfreq/event/rockchip-dfi.c ++++ b/drivers/devfreq/event/rockchip-dfi.c +@@ -18,25 +18,66 @@ + #include + #include + +-#include +- +-#define RK3399_DMC_NUM_CH 2 ++#define PX30_PMUGRF_OS_REG2 0x208 + ++#define RK3128_GRF_SOC_CON0 0x140 ++#define RK3128_GRF_OS_REG1 0x1cc ++#define RK3128_GRF_DFI_WRNUM 0x220 ++#define RK3128_GRF_DFI_RDNUM 0x224 ++#define RK3128_GRF_DFI_TIMERVAL 0x22c ++#define RK3128_DDR_MONITOR_EN ((1 << (16 + 6)) + (1 << 6)) ++#define RK3128_DDR_MONITOR_DISB ((1 << (16 + 6)) + (0 << 6)) ++ ++#define RK3288_PMU_SYS_REG2 0x9c ++#define RK3288_GRF_SOC_CON4 0x254 ++#define RK3288_GRF_SOC_STATUS(n) (0x280 + (n) * 4) ++#define RK3288_DFI_EN (0x30003 << 14) ++#define RK3288_DFI_DIS (0x30000 << 14) ++#define RK3288_LPDDR_SEL (0x10001 << 13) ++#define RK3288_DDR3_SEL (0x10000 << 13) ++ ++#define RK3328_GRF_OS_REG2 0x5d0 ++ ++#define RK3368_GRF_DDRC0_CON0 0x600 ++#define RK3368_GRF_SOC_STATUS5 0x494 ++#define RK3368_GRF_SOC_STATUS6 0x498 ++#define RK3368_GRF_SOC_STATUS8 0x4a0 ++#define RK3368_GRF_SOC_STATUS9 0x4a4 ++#define RK3368_GRF_SOC_STATUS10 0x4a8 ++#define RK3368_DFI_EN (0x30003 << 5) ++#define RK3368_DFI_DIS (0x30000 << 5) ++ ++#define MAX_DMC_NUM_CH 2 ++#define READ_DRAMTYPE_INFO(n) (((n) >> 13) & 0x7) ++#define READ_CH_INFO(n) (((n) >> 28) & 0x3) + /* DDRMON_CTRL */ +-#define DDRMON_CTRL 0x04 +-#define CLR_DDRMON_CTRL (0x1f0000 << 0) +-#define LPDDR4_EN (0x10001 << 4) +-#define HARDWARE_EN (0x10001 << 3) +-#define LPDDR3_EN (0x10001 << 2) +-#define SOFTWARE_EN (0x10001 << 1) +-#define SOFTWARE_DIS (0x10000 << 1) +-#define TIME_CNT_EN (0x10001 << 0) ++#define DDRMON_CTRL 0x04 ++#define CLR_DDRMON_CTRL (0x3f0000 << 0) ++#define DDR4_EN (0x10001 << 5) ++#define LPDDR4_EN (0x10001 << 4) ++#define HARDWARE_EN (0x10001 << 3) ++#define LPDDR2_3_EN (0x10001 << 2) ++#define SOFTWARE_EN (0x10001 << 1) ++#define SOFTWARE_DIS (0x10000 << 1) ++#define TIME_CNT_EN (0x10001 << 0) + + #define DDRMON_CH0_COUNT_NUM 0x28 + #define DDRMON_CH0_DFI_ACCESS_NUM 0x2c + #define DDRMON_CH1_COUNT_NUM 0x3c + #define DDRMON_CH1_DFI_ACCESS_NUM 0x40 + ++/* pmu grf */ ++#define PMUGRF_OS_REG2 0x308 ++ ++enum { ++ DDR4 = 0, ++ DDR3 = 3, ++ LPDDR2 = 5, ++ LPDDR3 = 6, ++ LPDDR4 = 7, ++ UNUSED = 0xFF ++}; ++ + struct dmc_usage { + u32 access; + u32 total; +@@ -50,33 +91,261 @@ struct dmc_usage { + struct rockchip_dfi { + struct devfreq_event_dev *edev; + struct devfreq_event_desc *desc; +- struct dmc_usage ch_usage[RK3399_DMC_NUM_CH]; ++ struct dmc_usage ch_usage[MAX_DMC_NUM_CH]; + struct device *dev; + void __iomem *regs; + struct regmap *regmap_pmu; ++ struct regmap *regmap_grf; ++ struct regmap *regmap_pmugrf; + struct clk *clk; ++ u32 dram_type; ++ /* ++ * available mask, 1: available, 0: not available ++ * each bit represent a channel ++ */ ++ u32 ch_msk; ++}; ++ ++static void rk3128_dfi_start_hardware_counter(struct devfreq_event_dev *edev) ++{ ++ struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); ++ ++ regmap_write(info->regmap_grf, ++ RK3128_GRF_SOC_CON0, ++ RK3128_DDR_MONITOR_EN); ++} ++ ++static void rk3128_dfi_stop_hardware_counter(struct devfreq_event_dev *edev) ++{ ++ struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); ++ ++ regmap_write(info->regmap_grf, ++ RK3128_GRF_SOC_CON0, ++ RK3128_DDR_MONITOR_DISB); ++} ++ ++static int rk3128_dfi_disable(struct devfreq_event_dev *edev) ++{ ++ rk3128_dfi_stop_hardware_counter(edev); ++ ++ return 0; ++} ++ ++static int rk3128_dfi_enable(struct devfreq_event_dev *edev) ++{ ++ rk3128_dfi_start_hardware_counter(edev); ++ ++ return 0; ++} ++ ++static int rk3128_dfi_set_event(struct devfreq_event_dev *edev) ++{ ++ return 0; ++} ++ ++static int rk3128_dfi_get_event(struct devfreq_event_dev *edev, ++ struct devfreq_event_data *edata) ++{ ++ struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); ++ unsigned long flags; ++ u32 dfi_wr, dfi_rd, dfi_timer; ++ ++ local_irq_save(flags); ++ ++ rk3128_dfi_stop_hardware_counter(edev); ++ ++ regmap_read(info->regmap_grf, RK3128_GRF_DFI_WRNUM, &dfi_wr); ++ regmap_read(info->regmap_grf, RK3128_GRF_DFI_RDNUM, &dfi_rd); ++ regmap_read(info->regmap_grf, RK3128_GRF_DFI_TIMERVAL, &dfi_timer); ++ ++ edata->load_count = (dfi_wr + dfi_rd) * 4; ++ edata->total_count = dfi_timer; ++ ++ rk3128_dfi_start_hardware_counter(edev); ++ ++ local_irq_restore(flags); ++ ++ return 0; ++} ++ ++static const struct devfreq_event_ops rk3128_dfi_ops = { ++ .disable = rk3128_dfi_disable, ++ .enable = rk3128_dfi_enable, ++ .get_event = rk3128_dfi_get_event, ++ .set_event = rk3128_dfi_set_event, ++}; ++ ++static void rk3288_dfi_start_hardware_counter(struct devfreq_event_dev *edev) ++{ ++ struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); ++ ++ regmap_write(info->regmap_grf, RK3288_GRF_SOC_CON4, RK3288_DFI_EN); ++} ++ ++static void rk3288_dfi_stop_hardware_counter(struct devfreq_event_dev *edev) ++{ ++ struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); ++ ++ regmap_write(info->regmap_grf, RK3288_GRF_SOC_CON4, RK3288_DFI_DIS); ++} ++ ++static int rk3288_dfi_disable(struct devfreq_event_dev *edev) ++{ ++ rk3288_dfi_stop_hardware_counter(edev); ++ ++ return 0; ++} ++ ++static int rk3288_dfi_enable(struct devfreq_event_dev *edev) ++{ ++ rk3288_dfi_start_hardware_counter(edev); ++ ++ return 0; ++} ++ ++static int rk3288_dfi_set_event(struct devfreq_event_dev *edev) ++{ ++ return 0; ++} ++ ++static int rk3288_dfi_get_busier_ch(struct devfreq_event_dev *edev) ++{ ++ struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); ++ u32 tmp, max = 0; ++ u32 i, busier_ch = 0; ++ u32 rd_count, wr_count, total_count; ++ ++ rk3288_dfi_stop_hardware_counter(edev); ++ ++ /* Find out which channel is busier */ ++ for (i = 0; i < MAX_DMC_NUM_CH; i++) { ++ if (!(info->ch_msk & BIT(i))) ++ continue; ++ regmap_read(info->regmap_grf, ++ RK3288_GRF_SOC_STATUS(11 + i * 4), &wr_count); ++ regmap_read(info->regmap_grf, ++ RK3288_GRF_SOC_STATUS(12 + i * 4), &rd_count); ++ regmap_read(info->regmap_grf, ++ RK3288_GRF_SOC_STATUS(14 + i * 4), &total_count); ++ info->ch_usage[i].access = (wr_count + rd_count) * 4; ++ info->ch_usage[i].total = total_count; ++ tmp = info->ch_usage[i].access; ++ if (tmp > max) { ++ busier_ch = i; ++ max = tmp; ++ } ++ } ++ rk3288_dfi_start_hardware_counter(edev); ++ ++ return busier_ch; ++} ++ ++static int rk3288_dfi_get_event(struct devfreq_event_dev *edev, ++ struct devfreq_event_data *edata) ++{ ++ struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); ++ int busier_ch; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ busier_ch = rk3288_dfi_get_busier_ch(edev); ++ local_irq_restore(flags); ++ ++ edata->load_count = info->ch_usage[busier_ch].access; ++ edata->total_count = info->ch_usage[busier_ch].total; ++ ++ return 0; ++} ++ ++static const struct devfreq_event_ops rk3288_dfi_ops = { ++ .disable = rk3288_dfi_disable, ++ .enable = rk3288_dfi_enable, ++ .get_event = rk3288_dfi_get_event, ++ .set_event = rk3288_dfi_set_event, ++}; ++ ++static void rk3368_dfi_start_hardware_counter(struct devfreq_event_dev *edev) ++{ ++ struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); ++ ++ regmap_write(info->regmap_grf, RK3368_GRF_DDRC0_CON0, RK3368_DFI_EN); ++} ++ ++static void rk3368_dfi_stop_hardware_counter(struct devfreq_event_dev *edev) ++{ ++ struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); ++ ++ regmap_write(info->regmap_grf, RK3368_GRF_DDRC0_CON0, RK3368_DFI_DIS); ++} ++ ++static int rk3368_dfi_disable(struct devfreq_event_dev *edev) ++{ ++ rk3368_dfi_stop_hardware_counter(edev); ++ ++ return 0; ++} ++ ++static int rk3368_dfi_enable(struct devfreq_event_dev *edev) ++{ ++ rk3368_dfi_start_hardware_counter(edev); ++ ++ return 0; ++} ++ ++static int rk3368_dfi_set_event(struct devfreq_event_dev *edev) ++{ ++ return 0; ++} ++ ++static int rk3368_dfi_get_event(struct devfreq_event_dev *edev, ++ struct devfreq_event_data *edata) ++{ ++ struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); ++ unsigned long flags; ++ u32 dfi0_wr, dfi0_rd, dfi1_wr, dfi1_rd, dfi_timer; ++ ++ local_irq_save(flags); ++ ++ rk3368_dfi_stop_hardware_counter(edev); ++ ++ regmap_read(info->regmap_grf, RK3368_GRF_SOC_STATUS5, &dfi0_wr); ++ regmap_read(info->regmap_grf, RK3368_GRF_SOC_STATUS6, &dfi0_rd); ++ regmap_read(info->regmap_grf, RK3368_GRF_SOC_STATUS9, &dfi1_wr); ++ regmap_read(info->regmap_grf, RK3368_GRF_SOC_STATUS10, &dfi1_rd); ++ regmap_read(info->regmap_grf, RK3368_GRF_SOC_STATUS8, &dfi_timer); ++ ++ edata->load_count = (dfi0_wr + dfi0_rd + dfi1_wr + dfi1_rd) * 2; ++ edata->total_count = dfi_timer; ++ ++ rk3368_dfi_start_hardware_counter(edev); ++ ++ local_irq_restore(flags); ++ ++ return 0; ++} ++ ++static const struct devfreq_event_ops rk3368_dfi_ops = { ++ .disable = rk3368_dfi_disable, ++ .enable = rk3368_dfi_enable, ++ .get_event = rk3368_dfi_get_event, ++ .set_event = rk3368_dfi_set_event, + }; + + static void rockchip_dfi_start_hardware_counter(struct devfreq_event_dev *edev) + { + struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); + void __iomem *dfi_regs = info->regs; +- u32 val; +- u32 ddr_type; +- +- /* get ddr type */ +- regmap_read(info->regmap_pmu, RK3399_PMUGRF_OS_REG2, &val); +- ddr_type = (val >> RK3399_PMUGRF_DDRTYPE_SHIFT) & +- RK3399_PMUGRF_DDRTYPE_MASK; + + /* clear DDRMON_CTRL setting */ + writel_relaxed(CLR_DDRMON_CTRL, dfi_regs + DDRMON_CTRL); + + /* set ddr type to dfi */ +- if (ddr_type == RK3399_PMUGRF_DDRTYPE_LPDDR3) +- writel_relaxed(LPDDR3_EN, dfi_regs + DDRMON_CTRL); +- else if (ddr_type == RK3399_PMUGRF_DDRTYPE_LPDDR4) ++ if (info->dram_type == LPDDR3 || info->dram_type == LPDDR2) ++ writel_relaxed(LPDDR2_3_EN, dfi_regs + DDRMON_CTRL); ++ else if (info->dram_type == LPDDR4) + writel_relaxed(LPDDR4_EN, dfi_regs + DDRMON_CTRL); ++ else if (info->dram_type == DDR4) ++ writel_relaxed(DDR4_EN, dfi_regs + DDRMON_CTRL); + + /* enable count, use software mode */ + writel_relaxed(SOFTWARE_EN, dfi_regs + DDRMON_CTRL); +@@ -100,12 +369,22 @@ static int rockchip_dfi_get_busier_ch(st + rockchip_dfi_stop_hardware_counter(edev); + + /* Find out which channel is busier */ +- for (i = 0; i < RK3399_DMC_NUM_CH; i++) { +- info->ch_usage[i].access = readl_relaxed(dfi_regs + +- DDRMON_CH0_DFI_ACCESS_NUM + i * 20) * 4; ++ for (i = 0; i < MAX_DMC_NUM_CH; i++) { ++ if (!(info->ch_msk & BIT(i))) ++ continue; ++ + info->ch_usage[i].total = readl_relaxed(dfi_regs + + DDRMON_CH0_COUNT_NUM + i * 20); +- tmp = info->ch_usage[i].access; ++ ++ /* LPDDR4 BL = 16,other DDR type BL = 8 */ ++ tmp = readl_relaxed(dfi_regs + ++ DDRMON_CH0_DFI_ACCESS_NUM + i * 20); ++ if (info->dram_type == LPDDR4) ++ tmp *= 8; ++ else ++ tmp *= 4; ++ info->ch_usage[i].access = tmp; ++ + if (tmp > max) { + busier_ch = i; + max = tmp; +@@ -121,7 +400,8 @@ static int rockchip_dfi_disable(struct d + struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); + + rockchip_dfi_stop_hardware_counter(edev); +- clk_disable_unprepare(info->clk); ++ if (info->clk) ++ clk_disable_unprepare(info->clk); + + return 0; + } +@@ -131,10 +411,13 @@ static int rockchip_dfi_enable(struct de + struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); + int ret; + +- ret = clk_prepare_enable(info->clk); +- if (ret) { +- dev_err(&edev->dev, "failed to enable dfi clk: %d\n", ret); +- return ret; ++ if (info->clk) { ++ ret = clk_prepare_enable(info->clk); ++ if (ret) { ++ dev_err(&edev->dev, "failed to enable dfi clk: %d\n", ++ ret); ++ return ret; ++ } + } + + rockchip_dfi_start_hardware_counter(edev); +@@ -151,8 +434,11 @@ static int rockchip_dfi_get_event(struct + { + struct rockchip_dfi *info = devfreq_event_get_drvdata(edev); + int busier_ch; ++ unsigned long flags; + ++ local_irq_save(flags); + busier_ch = rockchip_dfi_get_busier_ch(edev); ++ local_irq_restore(flags); + + edata->load_count = info->ch_usage[busier_ch].access; + edata->total_count = info->ch_usage[busier_ch].total; +@@ -167,22 +453,116 @@ static const struct devfreq_event_ops ro + .set_event = rockchip_dfi_set_event, + }; + +-static const struct of_device_id rockchip_dfi_id_match[] = { +- { .compatible = "rockchip,rk3399-dfi" }, +- { }, +-}; +-MODULE_DEVICE_TABLE(of, rockchip_dfi_id_match); ++static __init int px30_dfi_init(struct platform_device *pdev, ++ struct rockchip_dfi *data, ++ struct devfreq_event_desc *desc) ++{ ++ struct device_node *np = pdev->dev.of_node, *node; ++ struct resource *res; ++ u32 val; + +-static int rockchip_dfi_probe(struct platform_device *pdev) ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ data->regs = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(data->regs)) ++ return PTR_ERR(data->regs); ++ ++ node = of_parse_phandle(np, "rockchip,pmugrf", 0); ++ if (node) { ++ data->regmap_pmugrf = syscon_node_to_regmap(node); ++ if (IS_ERR(data->regmap_pmugrf)) ++ return PTR_ERR(data->regmap_pmugrf); ++ } ++ ++ regmap_read(data->regmap_pmugrf, PX30_PMUGRF_OS_REG2, &val); ++ data->dram_type = READ_DRAMTYPE_INFO(val); ++ data->ch_msk = 1; ++ data->clk = NULL; ++ ++ desc->ops = &rockchip_dfi_ops; ++ ++ return 0; ++} ++ ++static __init int rk3128_dfi_init(struct platform_device *pdev, ++ struct rockchip_dfi *data, ++ struct devfreq_event_desc *desc) + { +- struct device *dev = &pdev->dev; +- struct rockchip_dfi *data; +- struct devfreq_event_desc *desc; + struct device_node *np = pdev->dev.of_node, *node; + +- data = devm_kzalloc(dev, sizeof(struct rockchip_dfi), GFP_KERNEL); +- if (!data) +- return -ENOMEM; ++ node = of_parse_phandle(np, "rockchip,grf", 0); ++ if (node) { ++ data->regmap_grf = syscon_node_to_regmap(node); ++ if (IS_ERR(data->regmap_grf)) ++ return PTR_ERR(data->regmap_grf); ++ } ++ ++ desc->ops = &rk3128_dfi_ops; ++ ++ return 0; ++} ++ ++static __init int rk3288_dfi_init(struct platform_device *pdev, ++ struct rockchip_dfi *data, ++ struct devfreq_event_desc *desc) ++{ ++ struct device_node *np = pdev->dev.of_node, *node; ++ u32 val; ++ ++ node = of_parse_phandle(np, "rockchip,pmu", 0); ++ if (node) { ++ data->regmap_pmu = syscon_node_to_regmap(node); ++ if (IS_ERR(data->regmap_pmu)) ++ return PTR_ERR(data->regmap_pmu); ++ } ++ ++ node = of_parse_phandle(np, "rockchip,grf", 0); ++ if (node) { ++ data->regmap_grf = syscon_node_to_regmap(node); ++ if (IS_ERR(data->regmap_grf)) ++ return PTR_ERR(data->regmap_grf); ++ } ++ ++ regmap_read(data->regmap_pmu, RK3288_PMU_SYS_REG2, &val); ++ data->dram_type = READ_DRAMTYPE_INFO(val); ++ data->ch_msk = READ_CH_INFO(val); ++ ++ if (data->dram_type == DDR3) ++ regmap_write(data->regmap_grf, RK3288_GRF_SOC_CON4, ++ RK3288_DDR3_SEL); ++ else ++ regmap_write(data->regmap_grf, RK3288_GRF_SOC_CON4, ++ RK3288_LPDDR_SEL); ++ ++ desc->ops = &rk3288_dfi_ops; ++ ++ return 0; ++} ++ ++static __init int rk3368_dfi_init(struct platform_device *pdev, ++ struct rockchip_dfi *data, ++ struct devfreq_event_desc *desc) ++{ ++ struct device *dev = &pdev->dev; ++ ++ if (!dev->parent || !dev->parent->of_node) ++ return -EINVAL; ++ ++ data->regmap_grf = syscon_node_to_regmap(dev->parent->of_node); ++ if (IS_ERR(data->regmap_grf)) ++ return PTR_ERR(data->regmap_grf); ++ ++ desc->ops = &rk3368_dfi_ops; ++ ++ return 0; ++} ++ ++static __init int rockchip_dfi_init(struct platform_device *pdev, ++ struct rockchip_dfi *data, ++ struct devfreq_event_desc *desc) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = pdev->dev.of_node, *node; ++ u32 val; + + data->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(data->regs)) +@@ -202,21 +582,97 @@ static int rockchip_dfi_probe(struct pla + if (IS_ERR(data->regmap_pmu)) + return PTR_ERR(data->regmap_pmu); + } +- data->dev = dev; ++ ++ regmap_read(data->regmap_pmu, PMUGRF_OS_REG2, &val); ++ data->dram_type = READ_DRAMTYPE_INFO(val); ++ data->ch_msk = READ_CH_INFO(val); ++ ++ desc->ops = &rockchip_dfi_ops; ++ ++ return 0; ++} ++ ++static __init int rk3328_dfi_init(struct platform_device *pdev, ++ struct rockchip_dfi *data, ++ struct devfreq_event_desc *desc) ++{ ++ struct device_node *np = pdev->dev.of_node, *node; ++ struct resource *res; ++ u32 val; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ data->regs = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(data->regs)) ++ return PTR_ERR(data->regs); ++ ++ node = of_parse_phandle(np, "rockchip,grf", 0); ++ if (node) { ++ data->regmap_grf = syscon_node_to_regmap(node); ++ if (IS_ERR(data->regmap_grf)) ++ return PTR_ERR(data->regmap_grf); ++ } ++ ++ regmap_read(data->regmap_grf, RK3328_GRF_OS_REG2, &val); ++ data->dram_type = READ_DRAMTYPE_INFO(val); ++ data->ch_msk = 1; ++ data->clk = NULL; ++ ++ desc->ops = &rockchip_dfi_ops; ++ ++ return 0; ++} ++ ++static const struct of_device_id rockchip_dfi_id_match[] = { ++ { .compatible = "rockchip,px30-dfi", .data = px30_dfi_init }, ++ { .compatible = "rockchip,rk1808-dfi", .data = px30_dfi_init }, ++ { .compatible = "rockchip,rk3128-dfi", .data = rk3128_dfi_init }, ++ { .compatible = "rockchip,rk3288-dfi", .data = rk3288_dfi_init }, ++ { .compatible = "rockchip,rk3328-dfi", .data = rk3328_dfi_init }, ++ { .compatible = "rockchip,rk3368-dfi", .data = rk3368_dfi_init }, ++ { .compatible = "rockchip,rk3399-dfi", .data = rockchip_dfi_init }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, rockchip_dfi_id_match); ++ ++static int rockchip_dfi_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct rockchip_dfi *data; ++ struct devfreq_event_desc *desc; ++ struct device_node *np = pdev->dev.of_node; ++ const struct of_device_id *match; ++ int (*init)(struct platform_device *pdev, struct rockchip_dfi *data, ++ struct devfreq_event_desc *desc); ++ ++ data = devm_kzalloc(dev, sizeof(struct rockchip_dfi), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; + + desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); + if (!desc) + return -ENOMEM; + +- desc->ops = &rockchip_dfi_ops; ++ match = of_match_node(rockchip_dfi_id_match, pdev->dev.of_node); ++ if (match) { ++ init = match->data; ++ if (init) { ++ if (init(pdev, data, desc)) ++ return -EINVAL; ++ } else { ++ return 0; ++ } ++ } else { ++ return 0; ++ } ++ + desc->driver_data = data; + desc->name = np->name; + data->desc = desc; ++ data->dev = dev; + +- data->edev = devm_devfreq_event_add_edev(&pdev->dev, desc); ++ data->edev = devm_devfreq_event_add_edev(dev, desc); + if (IS_ERR(data->edev)) { +- dev_err(&pdev->dev, +- "failed to add devfreq-event device\n"); ++ dev_err(dev, "failed to add devfreq-event device\n"); + return PTR_ERR(data->edev); + } + diff --git a/target/linux/rockchip/patches-5.19/0061-arm64-dts-rockchip-rk3328-add-dfi-node.patch b/target/linux/rockchip/patches-5.19/0061-arm64-dts-rockchip-rk3328-add-dfi-node.patch new file mode 100644 index 000000000..2ab20487a --- /dev/null +++ b/target/linux/rockchip/patches-5.19/0061-arm64-dts-rockchip-rk3328-add-dfi-node.patch @@ -0,0 +1,27 @@ +From f9ae6e992d3d9e80357fee7d65ba0fe2dd37ae1f Mon Sep 17 00:00:00 2001 +From: hmz007 +Date: Tue, 19 Nov 2019 14:21:51 +0800 +Subject: [PATCH] arm64: dts: rockchip: rk3328: add dfi node + +Signed-off-by: hmz007 +[adjusted commit title] +Signed-off-by: Tianling Shen +--- + arch/arm64/boot/dts/rockchip/rk3328.dtsi | 7 +++++++ + +--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi +@@ -1005,6 +1005,13 @@ + status = "disabled"; + }; + ++ dfi: dfi@ff790000 { ++ reg = <0x00 0xff790000 0x00 0x400>; ++ compatible = "rockchip,rk3328-dfi"; ++ rockchip,grf = <&grf>; ++ status = "disabled"; ++ }; ++ + gic: interrupt-controller@ff811000 { + compatible = "arm,gic-400"; + #interrupt-cells = <3>; diff --git a/target/linux/rockchip/patches-5.19/0062-arm64-dts-nanopi-r2s-add-rk3328-dmc-relate-node.patch b/target/linux/rockchip/patches-5.19/0062-arm64-dts-nanopi-r2s-add-rk3328-dmc-relate-node.patch new file mode 100644 index 000000000..2e36792ac --- /dev/null +++ b/target/linux/rockchip/patches-5.19/0062-arm64-dts-nanopi-r2s-add-rk3328-dmc-relate-node.patch @@ -0,0 +1,126 @@ +From f9ae6e992d3d9e80357fee7d65ba0fe2dd37ae1f Mon Sep 17 00:00:00 2001 +From: hmz007 +Date: Tue, 19 Nov 2019 14:21:51 +0800 +Subject: [PATCH] arm64: dts: nanopi-r2: add rk3328-dmc relate node + +Signed-off-by: hmz007 +--- + .../rockchip/rk3328-dram-default-timing.dtsi | 311 ++++++++++++++++++ + .../dts/rockchip/rk3328-nanopi-r2-common.dtsi | 85 ++++- + include/dt-bindings/clock/rockchip-ddr.h | 63 ++++ + include/dt-bindings/memory/rk3328-dram.h | 159 +++++++++ + 4 files changed, 617 insertions(+), 1 deletion(-) + create mode 100644 arch/arm64/boot/dts/rockchip/rk3328-dram-default-timing.dtsi + create mode 100644 include/dt-bindings/clock/rockchip-ddr.h + create mode 100644 include/dt-bindings/memory/rk3328-dram.h + +--- a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts +@@ -7,6 +7,7 @@ + + #include + #include ++#include "rk3328-dram-nanopi2-timing.dtsi" + #include "rk3328.dtsi" + + / { +@@ -121,6 +122,72 @@ + regulator-boot-on; + vin-supply = <&vdd_5v>; + }; ++ ++ dmc: dmc { ++ compatible = "rockchip,rk3328-dmc"; ++ devfreq-events = <&dfi>; ++ center-supply = <&vdd_log>; ++ clocks = <&cru SCLK_DDRCLK>; ++ clock-names = "dmc_clk"; ++ operating-points-v2 = <&dmc_opp_table>; ++ ddr_timing = <&ddr_timing>; ++ upthreshold = <40>; ++ downdifferential = <20>; ++ auto-min-freq = <786000>; ++ auto-freq-en = <0>; ++ #cooling-cells = <2>; ++ status = "okay"; ++ ++ ddr_power_model: ddr_power_model { ++ compatible = "ddr_power_model"; ++ dynamic-power-coefficient = <120>; ++ static-power-coefficient = <200>; ++ ts = <32000 4700 (-80) 2>; ++ thermal-zone = "soc-thermal"; ++ }; ++ }; ++ ++ dmc_opp_table: dmc-opp-table { ++ compatible = "operating-points-v2"; ++ ++ rockchip,leakage-voltage-sel = < ++ 1 10 0 ++ 11 254 1 ++ >; ++ nvmem-cells = <&logic_leakage>; ++ nvmem-cell-names = "ddr_leakage"; ++ ++ opp-786000000 { ++ opp-hz = /bits/ 64 <786000000>; ++ opp-microvolt = <1075000>; ++ opp-microvolt-L0 = <1075000>; ++ opp-microvolt-L1 = <1050000>; ++ }; ++ opp-798000000 { ++ opp-hz = /bits/ 64 <798000000>; ++ opp-microvolt = <1075000>; ++ opp-microvolt-L0 = <1075000>; ++ opp-microvolt-L1 = <1050000>; ++ }; ++ opp-840000000 { ++ opp-hz = /bits/ 64 <840000000>; ++ opp-microvolt = <1075000>; ++ opp-microvolt-L0 = <1075000>; ++ opp-microvolt-L1 = <1050000>; ++ }; ++ opp-924000000 { ++ opp-hz = /bits/ 64 <924000000>; ++ opp-microvolt = <1100000>; ++ opp-microvolt-L0 = <1100000>; ++ opp-microvolt-L1 = <1075000>; ++ }; ++ opp-1056000000 { ++ opp-hz = /bits/ 64 <1056000000>; ++ opp-microvolt = <1175000>; ++ opp-microvolt-L0 = <1175000>; ++ opp-microvolt-L1 = <1150000>; ++ }; ++ }; + }; + + &cpu0 { +@@ -139,6 +206,10 @@ + cpu-supply = <&vdd_arm>; + }; + ++&dfi { ++ status = "okay"; ++}; ++ + &display_subsystem { + status = "disabled"; + }; +@@ -202,6 +273,7 @@ + regulator-name = "vdd_log"; + regulator-always-on; + regulator-boot-on; ++ regulator-init-microvolt = <1075000>; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1450000>; + regulator-ramp-delay = <12500>; +@@ -216,6 +288,7 @@ + regulator-name = "vdd_arm"; + regulator-always-on; + regulator-boot-on; ++ regulator-init-microvolt = <1225000>; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1450000>; + regulator-ramp-delay = <12500>; diff --git a/target/linux/rockchip/patches-5.19/0063-drv-net-phy-add-JLSemi-jl2xxx-driver.patch b/target/linux/rockchip/patches-5.19/0063-drv-net-phy-add-JLSemi-jl2xxx-driver.patch new file mode 100644 index 000000000..e2fb70694 --- /dev/null +++ b/target/linux/rockchip/patches-5.19/0063-drv-net-phy-add-JLSemi-jl2xxx-driver.patch @@ -0,0 +1,702 @@ +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -260,6 +260,11 @@ config INTEL_XWAY_PHY + PEF 7061, PEF 7071 and PEF 7072 or integrated into the Intel + SoCs xRX200, xRX300, xRX330, xRX350 and xRX550. + ++config JLSEMI_JL2XX1_PHY ++ tristate "JLSemi JL2XX1 PHYs" ++ help ++ Currently supports the JLSemi jl2xx1 PHYs. ++ + config LSI_ET1011C_PHY + tristate "LSI ET1011C PHY" + help +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -72,6 +72,8 @@ obj-$(CONFIG_DP83TC811_PHY) += dp83tc811 + obj-$(CONFIG_FIXED_PHY) += fixed_phy.o + obj-$(CONFIG_ICPLUS_PHY) += icplus.o + obj-$(CONFIG_INTEL_XWAY_PHY) += intel-xway.o ++obj-$(CONFIG_JLSEMI_JL2XX1_PHY) += jl2xx1.o ++jl2xx1-objs := jl2xxx.o jl2xxx-core.o + obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o + obj-$(CONFIG_LXT_PHY) += lxt.o + obj-$(CONFIG_MARVELL_10G_PHY) += marvell10g.o +--- /dev/null ++++ b/drivers/net/phy/jl2xxx-core.c +@@ -0,0 +1,438 @@ ++/* ++ * Copyright (C) 2021 JLSemi Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation version 2. ++ * ++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any ++ * kind, whether express or implied; without even the implied warranty ++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++#include "jl2xxx-core.h" ++#include ++#include ++#include ++#include ++ ++#define RGMII_CTRL_PAGE 171 ++#define RGMII_CTRL_REG 17 ++#define RGMII_TX_SW_RSTN BIT(14) ++#define RGMII_ERR_STAS BIT(3) ++#define RGMII_TX_CTR_EN BIT(1) ++ ++#define RGMII_STATUS_PAGE 166 ++#define RGMII_STATUS_REG 18 ++ ++#define BASIC_PAGE 0 ++#define BMCR_REG 0 ++#define SOFT_RESET BIT(15) ++#define SPEED_LSB BIT(13) ++#define AUTONEG_EN BIT(12) ++#define SPEED_MSB BIT(6) ++ ++#define DIG_PAGE 201 ++#define DIG_REG 17 ++#define CLK_10M_EN BIT(15) ++#define DAC_OUT_SEL_MSB BIT(1) ++#define DAC_OUT_SEL_LSB BIT(0) ++ ++/************************* Configuration section *************************/ ++ ++ ++/************************* JLSemi iteration code *************************/ ++ ++/* Patch for version: def2 */ ++uint32_t init_data[] = { ++ 0x1f00a0, 0x1903f3, 0x1f0012, 0x150100, 0x1f00ad, 0x100000, 0x11e0c6, 0x1f00a0, 0x1903fb, 0x1903fb, ++ 0x1903fb, 0x1903fb, 0x1903fb, 0x1903fb, 0x1903fb, 0x1903fb, 0x1f00ad, 0x110000, 0x120400, 0x130093, ++ 0x140000, 0x150193, 0x160000, 0x170213, 0x180000, 0x12040c, 0x130293, 0x140000, 0x150313, 0x160000, ++ 0x170393, 0x180000, 0x120418, 0x130413, 0x140000, 0x150493, 0x160000, 0x170513, 0x180000, 0x120424, ++ 0x130593, 0x140000, 0x150613, 0x160000, 0x170693, 0x180000, 0x120430, 0x130713, 0x140000, 0x150793, ++ 0x160000, 0x171137, 0x180000, 0x12043c, 0x13006f, 0x140060, 0x15a001, 0x160113, 0x17fd41, 0x18d026, ++ 0x120448, 0x13d406, 0x14d222, 0x1517b7, 0x160800, 0x17aa23, 0x189407, 0x120454, 0x130713, 0x1430f0, ++ 0x1567b7, 0x160800, 0x17a423, 0x1846e7, 0x120460, 0x13a703, 0x14a587, 0x156685, 0x168f55, 0x17ac23, ++ 0x18a4e7, 0x12046c, 0x1367b9, 0x145737, 0x150800, 0x168793, 0x17ef27, 0x182023, 0x120478, 0x1374f7, ++ 0x1407b7, 0x150800, 0x165bfc, 0x17d493, 0x180037, 0x120484, 0x13f493, 0x141f04, 0x15f793, 0x1607f7, ++ 0x178fc5, 0x18c03e, 0x120490, 0x134702, 0x140793, 0x150210, 0x160763, 0x1700f7, 0x180793, 0x12049c, ++ 0x130270, 0x140c63, 0x1530f7, 0x16a001, 0x1707b7, 0x180002, 0x1204a8, 0x138793, 0x146967, 0x15c83e, ++ 0x1617b7, 0x170002, 0x188793, 0x1204b4, 0x13e567, 0x14c43e, 0x1537b7, 0x160002, 0x178793, 0x186867, ++ 0x1204c0, 0x13c23e, 0x1447b7, 0x150002, 0x168793, 0x17e9a7, 0x1866b7, 0x1204cc, 0x130800, 0x14ca3e, ++ 0x15a783, 0x166d86, 0x1775c1, 0x188713, 0x1204d8, 0x130ff5, 0x148ff9, 0x156735, 0x160713, 0x178007, ++ 0x188fd9, 0x1204e4, 0x13ac23, 0x146cf6, 0x15a783, 0x1665c6, 0x175737, 0x180800, 0x1204f0, 0x136611, ++ 0x14f793, 0x15f0f7, 0x16e793, 0x170807, 0x18ae23, 0x1204fc, 0x1364f6, 0x142783, 0x155c47, 0x169bf5, ++ 0x172223, 0x185cf7, 0x120508, 0x13a703, 0x14f5c6, 0x158f51, 0x16ae23, 0x17f4e6, 0x180737, 0x120514, ++ 0x130809, 0x14433c, 0x158fd1, 0x16c33c, 0x170637, 0x180800, 0x120520, 0x134a74, 0x14679d, 0x158793, ++ 0x160e07, 0x179ae1, 0x18e693, 0x12052c, 0x130036, 0x14ca74, 0x154678, 0x1676e1, 0x178693, 0x185006, ++ 0x120538, 0x138ff9, 0x148fd5, 0x1507c2, 0x168f6d, 0x1783c1, 0x188fd9, 0x120544, 0x13c67c, 0x140713, ++ 0x151000, 0x160793, 0x170000, 0x189c23, 0x120550, 0x1324e7, 0x140713, 0x151010, 0x169123, 0x1726e7, ++ 0x18470d, 0x12055c, 0x13c63a, 0x144702, 0x158d23, 0x162407, 0x17a223, 0x182607, 0x120568, 0x130793, ++ 0x140270, 0x150413, 0x160000, 0x171463, 0x1800f7, 0x120574, 0x134789, 0x14c63e, 0x154709, 0x16cc3a, ++ 0x174702, 0x180793, 0x120580, 0x130270, 0x141463, 0x1500f7, 0x16478d, 0x17cc3e, 0x180513, 0x12058c, ++ 0x130000, 0x144792, 0x154581, 0x164485, 0x179782, 0x184018, 0x120598, 0x131775, 0x14e563, 0x1502e4, ++ 0x162703, 0x170a04, 0x181163, 0x1205a4, 0x130297, 0x144818, 0x150563, 0x160097, 0x1747a2, 0x18c804, ++ 0x1205b0, 0x139782, 0x1466b7, 0x150800, 0x16a703, 0x174c46, 0x189b71, 0x1205bc, 0x136713, 0x140027, ++ 0x15a223, 0x164ce6, 0x174783, 0x180fd4, 0x1205c8, 0x13c7b9, 0x142683, 0x151004, 0x164745, 0x179763, ++ 0x1820e6, 0x1205d4, 0x133737, 0x140822, 0x152683, 0x163007, 0x177645, 0x18167d, 0x1205e0, 0x138ef1, ++ 0x142023, 0x1530d7, 0x162683, 0x172807, 0x18e693, 0x1205ec, 0x131006, 0x142023, 0x1528d7, 0x162683, ++ 0x173807, 0x18e693, 0x1205f8, 0x131006, 0x142023, 0x1538d7, 0x162683, 0x174007, 0x18e693, 0x120604, ++ 0x131006, 0x142023, 0x1540d7, 0x162683, 0x174807, 0x18e693, 0x120610, 0x131006, 0x142023, 0x1548d7, ++ 0x1656b7, 0x170800, 0x18a703, 0x12061c, 0x133486, 0x14830d, 0x158b05, 0x16cf01, 0x17a703, 0x185c46, ++ 0x120628, 0x137671, 0x14167d, 0x158f71, 0x166611, 0x17a223, 0x185ce6, 0x120634, 0x138f51, 0x14a223, ++ 0x155ce6, 0x162703, 0x171084, 0x1846b2, 0x120640, 0x131c63, 0x1402d7, 0x153737, 0x160822, 0x172683, ++ 0x182807, 0x12064c, 0x13e693, 0x140016, 0x152023, 0x1628d7, 0x172683, 0x183807, 0x120658, 0x13e693, ++ 0x140016, 0x152023, 0x1638d7, 0x172683, 0x184007, 0x120664, 0x13e693, 0x140016, 0x152023, 0x1640d7, ++ 0x172683, 0x184807, 0x120670, 0x13e693, 0x140016, 0x152023, 0x1648d7, 0x172703, 0x181004, 0x12067c, ++ 0x1346b2, 0x149c63, 0x151ae6, 0x160737, 0x170800, 0x184b78, 0x120688, 0x130693, 0x140ff0, 0x15463d, ++ 0x168b1d, 0x17ce3a, 0x1852b7, 0x120694, 0x130800, 0x144701, 0x154389, 0x16408d, 0x174311, 0x180537, ++ 0x1206a0, 0x130820, 0x141593, 0x150077, 0x1695aa, 0x17418c, 0x184572, 0x1206ac, 0x1305c2, 0x1481c1, ++ 0x1581a9, 0x167763, 0x1700b5, 0x189533, 0x1206b8, 0x1300e4, 0x144513, 0x15fff5, 0x168e69, 0x170537, ++ 0x180800, 0x1206c4, 0x134568, 0x148121, 0x15893d, 0x167463, 0x1702b5, 0x18a583, 0x1206d0, 0x1306c2, ++ 0x140763, 0x151277, 0x160a63, 0x171217, 0x1805c2, 0x1206dc, 0x1381c1, 0x14818d, 0x150d63, 0x161097, ++ 0x178985, 0x180586, 0x1206e8, 0x1395b3, 0x1400b4, 0x15c593, 0x16fff5, 0x178eed, 0x180705, 0x1206f4, ++ 0x1315e3, 0x14fa67, 0x1535b7, 0x160822, 0x17a703, 0x183005, 0x120700, 0x13757d, 0x148a3d, 0x150513, ++ 0x160ff5, 0x178f69, 0x180622, 0x12070c, 0x138e59, 0x14a023, 0x1530c5, 0x168637, 0x170800, 0x185a38, ++ 0x120718, 0x1375c1, 0x14f693, 0x150ff6, 0x168593, 0x170ff5, 0x188f6d, 0x120724, 0x1306a2, 0x148ed9, ++ 0x15da34, 0x164682, 0x170713, 0x180210, 0x120730, 0x139163, 0x140ee6, 0x154711, 0x16e391, 0x17471d, ++ 0x182023, 0x12073c, 0x1310e4, 0x142683, 0x150a04, 0x16471d, 0x179e63, 0x1800e6, 0x120748, 0x136737, ++ 0x140800, 0x152703, 0x164cc7, 0x170693, 0x184000, 0x120754, 0x137713, 0x144807, 0x151463, 0x1600d7, ++ 0x172223, 0x180e04, 0x120760, 0x134018, 0x141163, 0x150497, 0x165703, 0x1700c4, 0x181793, 0x12076c, ++ 0x130117, 0x14db63, 0x150207, 0x168737, 0x170800, 0x184778, 0x120778, 0x137713, 0x140807, 0x15e705, ++ 0x160513, 0x170000, 0x184792, 0x120784, 0x134581, 0x149782, 0x1547a2, 0x164711, 0x17c818, 0x18c004, ++ 0x120790, 0x130d23, 0x140094, 0x150ca3, 0x160004, 0x179782, 0x1856b7, 0x12079c, 0x130800, 0x1442b8, ++ 0x159b71, 0x16c2b8, 0x170513, 0x180000, 0x1207a8, 0x1347d2, 0x149782, 0x154703, 0x162684, 0x1703e3, ++ 0x18de07, 0x1207b4, 0x13bbd9, 0x1407b7, 0x150002, 0x168793, 0x1765c7, 0x18c83e, 0x1207c0, 0x1327b7, ++ 0x140002, 0x158793, 0x16dae7, 0x17c43e, 0x1847b7, 0x1207cc, 0x130002, 0x148793, 0x151427, 0x16c23e, ++ 0x1757b7, 0x180002, 0x1207d8, 0x138793, 0x149867, 0x15b1fd, 0x162683, 0x171504, 0x184709, 0x1207e4, ++ 0x1399e3, 0x14e2e6, 0x1536b7, 0x160822, 0x17a703, 0x183006, 0x1207f0, 0x13663d, 0x148f51, 0x15a023, ++ 0x1630e6, 0x17bd39, 0x18c593, 0x1207fc, 0x130015, 0x14b5dd, 0x158991, 0x1635b3, 0x1700b0, 0x180589, ++ 0x120808, 0x13bdf9, 0x148991, 0x15b593, 0x160015, 0x17bfdd, 0x180737, 0x120814, 0x130800, 0x144f28, ++ 0x15cf89, 0x1647c2, 0x17893d, 0x189782, 0x120820, 0x1347e2, 0x140713, 0x151000, 0x162223, 0x1710e4, ++ 0x182423, 0x12082c, 0x1310f4, 0x14474d, 0x15b729, 0x168111, 0x17b7dd, 0x1814e3, 0x120838, 0x13f097, ++ 0x140737, 0x150800, 0x164770, 0x171713, 0x180106, 0x120844, 0x135d63, 0x140607, 0x1585b7, 0x160800, ++ 0x17a683, 0x180d05, 0x120850, 0x1372c5, 0x147313, 0x1500f6, 0x1612fd, 0x17a703, 0x180d45, 0x12085c, ++ 0x131513, 0x1400c3, 0x15f6b3, 0x160056, 0x178ec9, 0x18757d, 0x120868, 0x130393, 0x140ff5, 0x151293, ++ 0x160083, 0x17f6b3, 0x180076, 0x120874, 0x139b41, 0x148211, 0x15e2b3, 0x160056, 0x171093, 0x180043, ++ 0x120880, 0x137693, 0x140016, 0x156333, 0x160067, 0x170613, 0x187ff5, 0x12088c, 0x139713, 0x1400b6, ++ 0x157633, 0x1600c3, 0x178e59, 0x189513, 0x120898, 0x1300a6, 0x147613, 0x159ff6, 0x169713, 0x170096, ++ 0x188e49, 0x1208a4, 0x13f293, 0x14f0f2, 0x158e59, 0x16e2b3, 0x170012, 0x1806a2, 0x1208b0, 0x137613, ++ 0x14eff6, 0x158e55, 0x16a823, 0x170c55, 0x18aa23, 0x1208bc, 0x130cc5, 0x1480e3, 0x15e807, 0x1646b7, ++ 0x170822, 0x18a703, 0x1208c8, 0x13f006, 0x149b61, 0x156713, 0x160027, 0x17a023, 0x18f0e6, 0x1208d4, ++ 0x13b5ad, 0x140000, 0x150000, 0x160000, 0x170000, 0x180000, 0x110000, 0x120400, 0x104000, 0x1f0000, ++}; ++ ++int jl2xxx_pre_init(struct phy_device *phydev) ++{ ++ int i, j; ++ int regaddr, val; ++ int length = sizeof(init_data)/sizeof(init_data[0]); ++ ++ for (i = 0; i < length; i++) { ++ regaddr = ((init_data[i] >> 16) & 0xff); ++ val = (init_data[i] & 0xffff); ++ phy_write(phydev, regaddr, val); ++ if (regaddr == 0x18) { ++ phy_write(phydev, 0x10, 0x8006); ++ for (j = 0; j < 8; j++) { ++ if (phy_read(phydev, 0x10) == 0) { ++ break; ++ } ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++int enable_wol(struct phy_device *phydev) ++{ ++ jlsemi_set_bits(phydev, WOL_CTL_PAGE, ++ WOL_CTL_REG, WOL_EN); ++ ++ jlsemi_clear_bits(phydev, WOL_CTL_STAS_PAGE, ++ WOL_CTL_STAS_REG, WOL_CTL_EN); ++ ++ return 0; ++} ++ ++int disable_wol(struct phy_device *phydev) ++{ ++ jlsemi_clear_bits(phydev, WOL_CTL_PAGE, ++ WOL_CTL_REG, WOL_EN); ++ ++ jlsemi_set_bits(phydev, BASIC_PAGE, BMCR_REG, SOFT_RESET); ++ /* wait soft reset complete*/ ++ msleep(20); ++ ++ return 0; ++} ++ ++int setup_wol_low_polarity(struct phy_device *phydev) ++{ ++ jlsemi_clear_bits(phydev, WOL_CTL_STAS_PAGE, ++ WOL_CTL_STAS_REG, WOL_POLARITY); ++ return 0; ++} ++ ++int setup_wol_high_polarity(struct phy_device *phydev) ++{ ++ jlsemi_set_bits(phydev, WOL_CTL_STAS_PAGE, ++ WOL_CTL_STAS_REG, WOL_POLARITY); ++ return 0; ++} ++ ++int clear_wol_event(struct phy_device *phydev) ++{ ++ jlsemi_set_bits(phydev, WOL_CTL_STAS_PAGE, ++ WOL_CTL_STAS_REG, WOL_EVENT); ++ ++ jlsemi_clear_bits(phydev, WOL_CTL_STAS_PAGE, ++ WOL_CTL_STAS_REG, WOL_EVENT); ++ return 0; ++} ++ ++int store_mac_addr(struct phy_device *phydev) ++{ ++ int err; ++ ++ jlsemi_write_page(phydev, WOL_CTL_STAS_PAGE); ++ ++ /* Store the device address for the magic packet */ ++ err = phy_write(phydev, WOL_MAC_ADDR2_REG, ++ ((phydev->attached_dev->dev_addr[0] << 8) | ++ phydev->attached_dev->dev_addr[1])); ++ if (err < 0) ++ return err; ++ err = phy_write(phydev, WOL_MAC_ADDR1_REG, ++ ((phydev->attached_dev->dev_addr[2] << 8) | ++ phydev->attached_dev->dev_addr[3])); ++ if (err < 0) ++ return err; ++ err = phy_write(phydev, WOL_MAC_ADDR0_REG, ++ ((phydev->attached_dev->dev_addr[4] << 8) | ++ phydev->attached_dev->dev_addr[5])); ++ if (err < 0) ++ return err; ++ ++ /* change page to 0 */ ++ jlsemi_write_page(phydev, BASIC_PAGE); ++ ++ return 0; ++} ++ ++int config_phy_info(struct phy_device *phydev, ++ struct jl2xx1_priv *jl2xx1) ++{ ++ int val, major, minor; ++ ++ val = phy_read(phydev, 29); ++ if (val < 0) ++ return val; ++ ++ major = (val >> 7) & 0x1f; ++ minor = (val >> 0) & 0x7f; ++ /* major enlarge 10 */ ++ jl2xx1->sw_info = major * 10 + minor; ++ ++ return 0; ++} ++ ++/********************** Convenience function for phy **********************/ ++ ++/** ++ * jlsemi_write_page() - write the page register ++ * @phydev: a pointer to a &struct phy_device ++ * @page: page values ++ */ ++int jlsemi_write_page(struct phy_device *phydev, int page) ++{ ++ return phy_write(phydev, MII_JLSEMI_PHY_PAGE, page); ++} ++ ++/** ++ * jlsemi_read_page() - write the page register ++ * @phydev: a pointer to a &struct phy_device ++ * ++ * Return: get page values at present ++ */ ++int jlsemi_read_page(struct phy_device *phydev) ++{ ++ return phy_read(phydev, MII_JLSEMI_PHY_PAGE); ++} ++ ++/** ++ * __jlsemi_save_page() - save the page value ++ *@phydev: a pointer to a &struct phy_device ++ * ++ * Return: save page value ++ */ ++static inline int __jlsemi_save_page(struct phy_device *phydev) ++{ ++ return jlsemi_read_page(phydev); ++} ++ ++/** ++ * __jlsemi_select_page() - restore the page register ++ * @phydev: a pointer to a &struct phy_device ++ * @page: the page ++ * ++ * Return: ++ * @oldpgae: this is last page value ++ * @ret: if page is change it will return new page value ++ */ ++static inline int __jlsemi_select_page(struct phy_device *phydev, int page) ++{ ++ int ret, oldpage; ++ ++ oldpage = ret = __jlsemi_save_page(phydev); ++ if (ret < 0) ++ return ret; ++ ++ if (oldpage != page) { ++ ret = jlsemi_write_page(phydev, page); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return oldpage; ++} ++ ++/** ++ * __jlsemi_restore_page() - restore the page register ++ * @phydev: a pointer to a &struct phy_device ++ * @oldpage: the old page, return value from __jlsemi_save_page() or ++ * __jlsemi_select_page() ++ * @ret: operation's return code ++ * ++ * Returns: ++ * @oldpage if it was a negative value, otherwise ++ * @ret if it was a negative errno value, otherwise ++ * phy_write_page()'s negative value if it were in error, otherwise ++ * @ret ++ */ ++static inline int __jlsemi_restore_page(struct phy_device *phydev, ++ int oldpage, int ret) ++{ ++ int r; ++ ++ if (oldpage >= 0) { ++ r = jlsemi_write_page(phydev, oldpage); ++ ++ /* Propagate the operation return code if the page write ++ * was successful. ++ */ ++ if (ret >= 0 && r < 0) ++ ret = r; ++ } else { ++ /* Propagate the phy page selection error code */ ++ ret = oldpage; ++ } ++ ++ return ret; ++} ++ ++/** ++ * __jlsemi_modify_reg() - Convenience function for modifying a PHY register ++ * @phydev: a pointer to a &struct phy_device ++ * @regnum: register number ++ * @mask: bit mask of bits to clear ++ * @set: bit mask of bits to set ++ * ++ * Returns negative errno, 0 if there was no change, and 1 in case of change ++ */ ++static inline int __jlsemi_modify_reg(struct phy_device *phydev, ++ u32 regnum, u16 mask, u16 set) ++{ ++ int newval, ret; ++ ++ ret = phy_read(phydev, regnum); ++ if (ret < 0) ++ return ret; ++ ++ newval = (ret & ~mask) | set; ++ if (newval == ret) ++ return 0; ++ ++ ret = phy_write(phydev, regnum, newval); ++ ++ return ret < 0 ? ret : 1; ++} ++ ++/** ++ * jlsemi_modify_paged_reg() - Function for modifying a paged register ++ * @phydev: a pointer to a &struct phy_device ++ * @page: the page for the phy ++ * @regnum: register number ++ * @mask: bit mask of bits to clear ++ * @set: bit mask of bits to set ++ * ++ * Returns negative errno, 0 if there was no change, and 1 in case of change ++ */ ++int jlsemi_modify_paged_reg(struct phy_device *phydev, ++ int page, u32 regnum, ++ u16 mask, u16 set) ++{ ++ int ret = 0, oldpage; ++ ++ oldpage = __jlsemi_select_page(phydev, page); ++ if (oldpage >= 0) ++ ret = __jlsemi_modify_reg(phydev, regnum, mask, set); ++ ++ return __jlsemi_restore_page(phydev, oldpage, ret); ++} ++ ++/** ++ * jlsemi_set_bits() - Convenience function for setting bits in a PHY register ++ * @phydev: a pointer to a &struct phy_device ++ * @page: the page for the phy ++ * @regnum: register number to write ++ * @val: bits to set ++ */ ++int jlsemi_set_bits(struct phy_device *phydev, ++ int page, u32 regnum, u16 val) ++{ ++ return jlsemi_modify_paged_reg(phydev, page, regnum, 0, val); ++} ++ ++/** ++ * jlsemi_clear_bits - Convenience function for clearing bits in a PHY register ++ * @phydev: the phy_device struct ++ * @page: the page for the phy ++ * @regnum: register number to write ++ * @val: bits to clear ++ */ ++int jlsemi_clear_bits(struct phy_device *phydev, ++ int page, u32 regnum, u16 val) ++{ ++ return jlsemi_modify_paged_reg(phydev, page, regnum, val, 0); ++} ++ ++/** ++ * jlsemi_get_bit() - Convenience function for setting bits in a PHY register ++ * @phydev: a pointer to a &struct phy_device ++ * @page: the page for the phy ++ * @regnum: register number to write ++ * @val: bit to get ++ * ++ * Note: ++ * you only get one bit at meanwhile ++ * ++ */ ++int jlsemi_get_bit(struct phy_device *phydev, ++ int page, u32 regnum, u16 val) ++{ ++ int ret = 0, oldpage; ++ ++ oldpage = __jlsemi_select_page(phydev, page); ++ if (oldpage >= 0) ++ { ++ ret = phy_read(phydev, regnum); ++ if (ret < 0) ++ return ret; ++ ret = ((ret & val) == val) ? 1 : 0; ++ } ++ ++ return __jlsemi_restore_page(phydev, oldpage, ret); ++} +--- /dev/null ++++ b/drivers/net/phy/jl2xxx-core.h +@@ -0,0 +1,104 @@ ++/* ++ * Copyright (C) 2021 JLSemi Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation version 2. ++ * ++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any ++ * kind, whether express or implied; without even the implied warranty ++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++#ifndef _JLSEMI_CORE_H ++#define _JLSEMI_CORE_H ++ ++#include ++#include ++#include ++ ++#define JL2XX1_PHY_ID 0x937c4030 ++#define JLSEMI_PHY_ID_MASK 0xfffffff0 ++ ++#define JL2101_PHY_ID 0x937c4032 ++ ++#define MII_JLSEMI_PHY_PAGE 0x1f ++ ++#define WOL_CTL_PAGE 18 ++#define WOL_CTL_REG 21 ++#define WOL_CTL_STAS_PAGE 4608 ++#define WOL_CTL_STAS_REG 16 ++#define WOL_MAC_ADDR2_REG 17 ++#define WOL_MAC_ADDR1_REG 18 ++#define WOL_MAC_ADDR0_REG 19 ++#define WOL_EVENT BIT(1) ++#define WOL_POLARITY BIT(14) ++#define WOL_EN BIT(6) ++#define WOL_CTL_EN BIT(15) ++ ++ ++/************************* Configuration section *************************/ ++ ++#define JLSEMI_WOL_EN 0 ++ ++ ++/************************* JLSemi iteration code *************************/ ++struct jl2xx1_priv { ++ u16 sw_info; ++}; ++ ++int jl2xxx_pre_init(struct phy_device *phydev); ++ ++int config_phy_info(struct phy_device *phydev, ++ struct jl2xx1_priv *jl2xx1); ++ ++int check_rgmii(struct phy_device *phydev); ++ ++int dis_rgmii_tx_ctrl(struct phy_device *phydev); ++ ++int config_suspend(struct phy_device *phydev); ++ ++int config_resume(struct phy_device *phydev); ++ ++int enable_wol(struct phy_device *phydev); ++ ++int disable_wol(struct phy_device *phydev); ++ ++int setup_wol_low_polarity(struct phy_device *phydev); ++ ++int setup_wol_high_polarity(struct phy_device *phydev); ++ ++int clear_wol_event(struct phy_device *phydev); ++ ++int store_mac_addr(struct phy_device *phydev); ++ ++int software_version(struct phy_device *phydev); ++ ++ ++/********************** Convenience function for phy **********************/ ++ ++/* Notice: You should change page 0 when you When you call it after*/ ++int jlsemi_write_page(struct phy_device *phydev, int page); ++ ++int jlsemi_read_page(struct phy_device *phydev); ++ ++int jlsemi_modify_paged_reg(struct phy_device *phydev, ++ int page, u32 regnum, ++ u16 mask, u16 set); ++ ++int jlsemi_set_bits(struct phy_device *phydev, ++ int page, u32 regnum, u16 val); ++ ++int jlsemi_clear_bits(struct phy_device *phydev, ++ int page, u32 regnum, u16 val); ++ ++int jlsemi_get_bit(struct phy_device *phydev, ++ int page, u32 regnum, u16 val); ++ ++int jlsemi_drivers_register(struct phy_driver *phydrvs, int size); ++ ++void jlsemi_drivers_unregister(struct phy_driver *phydrvs, int size); ++ ++#endif /* _JLSEMI_CORE_H */ ++ +--- /dev/null ++++ b/drivers/net/phy/jl2xxx.c +@@ -0,0 +1,126 @@ ++/* ++ * drivers/net/phy/jlsemi.c ++ * ++ * Driver for JLSemi PHYs ++ * ++ * Author: Gangqiao Kuang ++ * ++ * Copyright (c) 2021 JingLue Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ */ ++#include "jl2xxx-core.h" ++#include ++#include ++#include ++ ++ ++MODULE_DESCRIPTION("JLSemi PHY driver"); ++MODULE_AUTHOR("Gangqiao Kuang"); ++MODULE_LICENSE("GPL"); ++ ++static int jlsemi_probe(struct phy_device *phydev) ++{ ++ int err; ++ ++ err = jl2xxx_pre_init(phydev); ++ ++ /* wait load complete*/ ++ msleep(20); ++ ++ return (err < 0) ? err : 0; ++} ++ ++#if JLSEMI_WOL_EN ++static void jlsemi_get_wol(struct phy_device *phydev, ++ struct ethtool_wolinfo *wol) ++{ ++ int wol_en; ++ ++ wol->supported = WAKE_MAGIC; ++ wol->wolopts = 0; ++ ++ wol_en = jlsemi_get_bit(phydev, WOL_CTL_PAGE, ++ WOL_CTL_REG, WOL_EN); ++ ++ if (wol_en) ++ wol->wolopts |= WAKE_MAGIC; ++} ++ ++static int jlsemi_set_wol(struct phy_device *phydev, ++ struct ethtool_wolinfo *wol) ++{ ++ int err; ++ ++ if (wol->wolopts & WAKE_MAGIC) { ++ err = enable_wol(phydev); ++ if (err < 0) ++ return err; ++ ++ err = clear_wol_event(phydev); ++ if (err < 0) ++ return err; ++ ++ err = setup_wol_high_polarity(phydev); ++ if (err < 0) ++ return err; ++ ++ err = store_mac_addr(phydev); ++ if (err < 0) ++ return err; ++ } else { ++ err = disable_wol(phydev); ++ if (err < 0) ++ return err; ++ ++ err = setup_wol_high_polarity(phydev); ++ if (err < 0) ++ return err; ++ ++ err = clear_wol_event(phydev); ++ if (err < 0) ++ return err; ++ } ++ ++ return 0; ++} ++#endif ++ ++static struct phy_driver jlsemi_driver[] = { ++ { ++ PHY_ID_MATCH_EXACT(JL2101_PHY_ID), ++ .name = "JL2101 Gigabit Ethernet", ++ /* PHY_BASIC_FEATURES */ ++ .features = PHY_GBIT_FEATURES, ++ .probe = jlsemi_probe, ++ #if JLSEMI_WOL_EN ++ .get_wol = jlsemi_get_wol, ++ .set_wol = jlsemi_set_wol, ++ #endif ++ }, ++ { ++ PHY_ID_MATCH_MODEL(JL2XX1_PHY_ID), ++ .name = "JL2xx1 Gigabit Ethernet", ++ /* PHY_BASIC_FEATURES */ ++ .features = PHY_GBIT_FEATURES, ++ .probe = jlsemi_probe, ++ #if JLSEMI_WOL_EN ++ .get_wol = jlsemi_get_wol, ++ .set_wol = jlsemi_set_wol, ++ #endif ++ }, ++}; ++ ++module_phy_driver(jlsemi_driver); ++ ++static struct mdio_device_id __maybe_unused jlsemi_tbl[] = { ++ { PHY_ID_MATCH_EXACT(JL2101_PHY_ID) }, ++ { PHY_ID_MATCH_MODEL(JL2XX1_PHY_ID) }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(mdio, jlsemi_tbl); diff --git a/target/linux/rockchip/patches-5.19/0900-arm-boot-add-dts-files.patch b/target/linux/rockchip/patches-5.19/0900-arm-boot-add-dts-files.patch new file mode 100644 index 000000000..eb2b744dc --- /dev/null +++ b/target/linux/rockchip/patches-5.19/0900-arm-boot-add-dts-files.patch @@ -0,0 +1,34 @@ +--- a/arch/arm64/boot/dts/rockchip/Makefile ++++ b/arch/arm64/boot/dts/rockchip/Makefile +@@ -9,8 +9,12 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3318-a9 + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3326-odroid-go2.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-a1.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-evb.dtb ++dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-doornet1.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-nanopi-neo3.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-nanopi-r2s.dtb ++dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-nanopi-r2c.dtb ++dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-orangepi-r1-plus.dtb ++dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-orangepi-r1-plus-lts.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-rock64.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-rock-pi-e.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3328-roc-cc.dtb +@@ -22,6 +26,8 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-or + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-px5-evb.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-r88.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-evb.dtb ++dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-doornet2.dtb ++dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-doornet2-4gb.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-ficus.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-firefly.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-gru-bob.dtb +@@ -40,6 +46,9 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-na + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-m4b.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-neo4.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-r4s.dtb ++dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-nanopi-r4se.dtb ++dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-guangmiao-g4c.dtb ++dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-rock-pi-4.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-orangepi.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-pinebook-pro.dtb + dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-puma-haikou.dtb diff --git a/target/linux/rockchip/patches-5.19/0901-rockchip-rk3399-overclock-to-2.2-1.8-GHz-for-NanoPi4.patch b/target/linux/rockchip/patches-5.19/0901-rockchip-rk3399-overclock-to-2.2-1.8-GHz-for-NanoPi4.patch new file mode 100644 index 000000000..87176a053 --- /dev/null +++ b/target/linux/rockchip/patches-5.19/0901-rockchip-rk3399-overclock-to-2.2-1.8-GHz-for-NanoPi4.patch @@ -0,0 +1,21 @@ +--- a/arch/arm64/boot/dts/rockchip/rk3399-doornet2.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-doornet2.dtsi +@@ -3,6 +3,7 @@ + /dts-v1/; + #include + #include "rk3399.dtsi" ++#include "rk3399-nanopi4-opp.dtsi" + + / { + chosen { +--- a/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi +@@ -14,7 +14,7 @@ + /dts-v1/; + #include + #include "rk3399.dtsi" +-#include "rk3399-opp.dtsi" ++#include "rk3399-nanopi4-opp.dtsi" + + / { + aliases { diff --git a/target/linux/rockchip/patches-5.19/0902-arm64-dts-rockchip-add-more-cpu-operating-points-for.patch b/target/linux/rockchip/patches-5.19/0902-arm64-dts-rockchip-add-more-cpu-operating-points-for.patch new file mode 100644 index 000000000..d9145299e --- /dev/null +++ b/target/linux/rockchip/patches-5.19/0902-arm64-dts-rockchip-add-more-cpu-operating-points-for.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Leonidas P. Papadakos +Date: Fri, 1 Mar 2019 21:55:53 +0200 +Subject: [PATCH v2] arm64: dts: rockchip: add more cpu operating points for + RK3328 + +This allows for greater max frequency on rk3328 boards, +increasing performance. + +It has been included in Armbian (a linux distibution for ARM boards) +for a while now without any reported issues + +https://github.com/armbian/build/blob/master/patch/kernel/rockchip64-default/enable-1392mhz-opp.patch +https://github.com/armbian/build/blob/master/patch/kernel/rockchip64-default/enable-1512mhz-opp.patch + +Signed-off-by: Leonidas P. Papadakos +--- + arch/arm64/boot/dts/rockchip/rk3328.dtsi | 15 +++++++++++++++ + 1 files changed, 15 insertions(+) + +--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi +@@ -140,6 +140,21 @@ + opp-microvolt = <1300000>; + clock-latency-ns = <40000>; + }; ++ opp-1392000000 { ++ opp-hz = /bits/ 64 <1392000000>; ++ opp-microvolt = <1350000>; ++ clock-latency-ns = <40000>; ++ }; ++ opp-1512000000 { ++ opp-hz = /bits/ 64 <1512000000>; ++ opp-microvolt = <1400000>; ++ clock-latency-ns = <40000>; ++ }; ++ opp-1608000000 { ++ opp-hz = /bits/ 64 <1608000000>; ++ opp-microvolt = <1450000>; ++ clock-latency-ns = <40000>; ++ }; + }; + + analog_sound: analog-sound { diff --git a/target/linux/rockchip/patches-5.19/0903-crypto-rockchip-permit-to-pass-self-tests.patch b/target/linux/rockchip/patches-5.19/0903-crypto-rockchip-permit-to-pass-self-tests.patch new file mode 100644 index 000000000..af346f09d --- /dev/null +++ b/target/linux/rockchip/patches-5.19/0903-crypto-rockchip-permit-to-pass-self-tests.patch @@ -0,0 +1,2419 @@ +From patchwork Wed Jul 6 09:03:40 2022 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: LABBE Corentin +X-Patchwork-Id: 12907886 +Return-Path: + +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from bombadil.infradead.org (bombadil.infradead.org + [198.137.202.133]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by smtp.lore.kernel.org (Postfix) with ESMTPS id 80701C43334 + for ; + Wed, 6 Jul 2022 10:21:13 +0000 (UTC) +DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; + d=lists.infradead.org; s=bombadil.20210309; h=Sender: + Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: + List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: + Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: + Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: + List-Owner; bh=w2ewNjuPH3tCNpBACI9xMFukG8dznlgGn9auxf/TbSQ=; b=NMnZMIilH6Rj6q + JBeFHcO/0vy9bRepjfvBprmkGHfP0tGg2cfWZeQccgiH3J4xRnkQ8JCi8RhG+amUdCBP677fEwXqL + XDvulNMteh+ACd3gAZ2pWy1qE0RBQIRDEIngwNqYTFB0IfP/7cMHrzRy4v5Ynx7nI/6rkfi7O2oWH + jUb0AaXqbIQFeD4t3sr8v5gFOHpbwbH2urceXPRviZtl67L3Ejc9yEpmZJBZc0u2/hI1MLLE5h8Ks + gnOq0NUJdvmH9pV3fxLEx5m5RPb5D6DaTAT05Sjbj3tICBtXcrvI0CfGiM6Py64YLwfHiJFFDbhp6 + ng01U9Kg047g0MgLntvw==; +Received: from localhost ([::1] helo=bombadil.infradead.org) + by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) + id 1o929R-008Ncf-Sj; Wed, 06 Jul 2022 10:20:58 +0000 +Received: from mail-wr1-x430.google.com ([2a00:1450:4864:20::430]) + by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) + id 1o90xZ-007bjU-2s + for linux-rockchip@lists.infradead.org; Wed, 06 Jul 2022 09:04:39 +0000 +Received: by mail-wr1-x430.google.com with SMTP id s1so21047035wra.9 + for ; + Wed, 06 Jul 2022 02:04:35 -0700 (PDT) +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=baylibre-com.20210112.gappssmtp.com; s=20210112; + h=from:to:cc:subject:date:message-id:in-reply-to:references + :mime-version:content-transfer-encoding; + bh=2nwWkT4441Zvq5igIAOKA8C0HAjPPXDmTRADPlAyhok=; + b=Pr3IXa8ExRhTFh+SPH7MrhQizXMmrRN4KOZzHqdYpWENJ96Ms04oBik0WfZbJ27egJ + ldxRn/lKH+72j5pIK0nS2nYnViD4t7mh4Zb1sOqM2u2kO5jOs6YQUThf4H4eI2Km2Ujk + DwddZ86xRnFapyFfMRqcT6ohi+6e0uc4u1C7mMTTJA/fIR7ogqFH26AfqYtb+NPy09S6 + Lqsl7Gej6g7TLBDiNG7TJFSX2PL0SMt1IdS4uGkcq1ucTSIZUoDqeFV0sk0icX109eD0 + +evOAKZrJ8Fcpr+vITTRyd9o5yoYy0tl+3ssElJnyQ3+12HdNMnyGRJT/M/jsAeeXFrC + 2s1g== +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20210112; + h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to + :references:mime-version:content-transfer-encoding; + bh=2nwWkT4441Zvq5igIAOKA8C0HAjPPXDmTRADPlAyhok=; + b=jrNkcu/YHsMg9g+c9DCMe2rYgZEjs2Kcrlvvla7WjME4uPIc42dSmgAaooVKGqfrOx + bmRlEpMseKnH+swTfgQT96HD72A1+GlBNgvGzgobVh9dE6qywC2hXeayy+6lvNQ04QDb + htuh/1tFPquCnMZrB6XkrBLtIoqngGlPObKutvylCovAOjcMfdpNkAbu6WXUdrVezesX + ipOA7nPpe1xK3xuRRarLWUtH0krfxDUMC3Zzv/ci7c9hqGq+wEV9+gofJqJnTbwHiAUU + XxtjOgZTFFruqo2Xh/aH1pz/dpOBlM77c+p9+BTiVbNjFR0uxH26+0CI2qLyeCpccvyL + Z5bg== +X-Gm-Message-State: AJIora+k2/Y0J3c5bRbTc8eO22Wszf2dEyzrIIniVBJBPx3Z+auKYN3q + rdqODKFBStTNE4iGSGyh2gI2yw== +X-Google-Smtp-Source: + AGRyM1uEESfBM2/+cx8O6PDi67ahL3H9B52KIeo6hugjBlO2PZU9E0Dg3m/zc4Jx7ArSkzmwQCEl3w== +X-Received: by 2002:a5d:6d0c:0:b0:21b:ccda:fc67 with SMTP id + e12-20020a5d6d0c000000b0021bccdafc67mr37250833wrq.246.1657098274092; + Wed, 06 Jul 2022 02:04:34 -0700 (PDT) +Received: from localhost.localdomain + (laubervilliers-658-1-213-31.w90-63.abo.wanadoo.fr. [90.63.244.31]) + by smtp.googlemail.com with ESMTPSA id + v11-20020adfe28b000000b0021d6ef34b2asm5230223wri.51.2022.07.06.02.04.33 + (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); + Wed, 06 Jul 2022 02:04:33 -0700 (PDT) +From: Corentin Labbe +To: heiko@sntech.de, + herbert@gondor.apana.org.au, + krzysztof.kozlowski+dt@linaro.org, + mturquette@baylibre.com, + p.zabel@pengutronix.de, + robh+dt@kernel.org, + sboyd@kernel.org +Cc: linux-rockchip@lists.infradead.org, + devicetree@vger.kernel.org, + linux-arm-kernel@lists.infradead.org, + linux-clk@vger.kernel.org, + linux-crypto@vger.kernel.org, + linux-kernel@vger.kernel.org, + john@metanate.com, + didi.debian@cknow.org, + Corentin Labbe +Subject: [PATCH v8 01/33] crypto: rockchip: use dev_err for error message + about interrupt +Date: Wed, 6 Jul 2022 09:03:40 +0000 +Message-Id: <20220706090412.806101-2-clabbe@baylibre.com> +X-Mailer: git-send-email 2.25.1 +In-Reply-To: <20220706090412.806101-1-clabbe@baylibre.com> +References: <20220706090412.806101-1-clabbe@baylibre.com> +MIME-Version: 1.0 +X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 +X-CRM114-CacheID: sfid-20220706_020437_385385_DD262621 +X-CRM114-Status: GOOD ( 11.86 ) +X-BeenThere: linux-rockchip@lists.infradead.org +X-Mailman-Version: 2.1.34 +Precedence: list +List-Id: Upstream kernel work for Rockchip platforms + +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Sender: "Linux-rockchip" +Errors-To: + linux-rockchip-bounces+linux-rockchip=archiver.kernel.org@lists.infradead.org + +Interrupt is mandatory so the message should be printed as error. + +Reviewed-by: John Keeping +Signed-off-by: Corentin Labbe +--- + drivers/crypto/rockchip/rk3288_crypto.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/crypto/rockchip/rk3288_crypto.c ++++ b/drivers/crypto/rockchip/rk3288_crypto.c +@@ -14,235 +14,162 @@ + #include + #include + #include ++#include + #include + #include + #include + +-static int rk_crypto_enable_clk(struct rk_crypto_info *dev) ++static struct rockchip_ip rocklist = { ++ .dev_list = LIST_HEAD_INIT(rocklist.dev_list), ++ .lock = __SPIN_LOCK_UNLOCKED(rocklist.lock), ++}; ++ ++struct rk_crypto_info *get_rk_crypto(void) + { +- int err; ++ struct rk_crypto_info *first; + +- err = clk_prepare_enable(dev->sclk); +- if (err) { +- dev_err(dev->dev, "[%s:%d], Couldn't enable clock sclk\n", +- __func__, __LINE__); +- goto err_return; +- } +- err = clk_prepare_enable(dev->aclk); +- if (err) { +- dev_err(dev->dev, "[%s:%d], Couldn't enable clock aclk\n", +- __func__, __LINE__); +- goto err_aclk; ++ spin_lock(&rocklist.lock); ++ first = list_first_entry_or_null(&rocklist.dev_list, ++ struct rk_crypto_info, list); ++ list_rotate_left(&rocklist.dev_list); ++ spin_unlock(&rocklist.lock); ++ return first; ++} ++ ++static const struct rk_variant rk3288_variant = { ++ .num_clks = 4, ++ .rkclks = { ++ { "sclk", 150000000}, + } +- err = clk_prepare_enable(dev->hclk); +- if (err) { +- dev_err(dev->dev, "[%s:%d], Couldn't enable clock hclk\n", +- __func__, __LINE__); +- goto err_hclk; +- } +- err = clk_prepare_enable(dev->dmaclk); +- if (err) { +- dev_err(dev->dev, "[%s:%d], Couldn't enable clock dmaclk\n", +- __func__, __LINE__); +- goto err_dmaclk; +- } +- return err; +-err_dmaclk: +- clk_disable_unprepare(dev->hclk); +-err_hclk: +- clk_disable_unprepare(dev->aclk); +-err_aclk: +- clk_disable_unprepare(dev->sclk); +-err_return: +- return err; +-} ++}; + +-static void rk_crypto_disable_clk(struct rk_crypto_info *dev) +-{ +- clk_disable_unprepare(dev->dmaclk); +- clk_disable_unprepare(dev->hclk); +- clk_disable_unprepare(dev->aclk); +- clk_disable_unprepare(dev->sclk); +-} +- +-static int check_alignment(struct scatterlist *sg_src, +- struct scatterlist *sg_dst, +- int align_mask) +-{ +- int in, out, align; +- +- in = IS_ALIGNED((uint32_t)sg_src->offset, 4) && +- IS_ALIGNED((uint32_t)sg_src->length, align_mask); +- if (!sg_dst) +- return in; +- out = IS_ALIGNED((uint32_t)sg_dst->offset, 4) && +- IS_ALIGNED((uint32_t)sg_dst->length, align_mask); +- align = in && out; +- +- return (align && (sg_src->length == sg_dst->length)); +-} +- +-static int rk_load_data(struct rk_crypto_info *dev, +- struct scatterlist *sg_src, +- struct scatterlist *sg_dst) +-{ +- unsigned int count; +- +- dev->aligned = dev->aligned ? +- check_alignment(sg_src, sg_dst, dev->align_size) : +- dev->aligned; +- if (dev->aligned) { +- count = min(dev->left_bytes, sg_src->length); +- dev->left_bytes -= count; +- +- if (!dma_map_sg(dev->dev, sg_src, 1, DMA_TO_DEVICE)) { +- dev_err(dev->dev, "[%s:%d] dma_map_sg(src) error\n", +- __func__, __LINE__); +- return -EINVAL; +- } +- dev->addr_in = sg_dma_address(sg_src); ++static const struct rk_variant rk3328_variant = { ++ .num_clks = 3, ++}; + +- if (sg_dst) { +- if (!dma_map_sg(dev->dev, sg_dst, 1, DMA_FROM_DEVICE)) { +- dev_err(dev->dev, +- "[%s:%d] dma_map_sg(dst) error\n", +- __func__, __LINE__); +- dma_unmap_sg(dev->dev, sg_src, 1, +- DMA_TO_DEVICE); +- return -EINVAL; +- } +- dev->addr_out = sg_dma_address(sg_dst); +- } +- } else { +- count = (dev->left_bytes > PAGE_SIZE) ? +- PAGE_SIZE : dev->left_bytes; +- +- if (!sg_pcopy_to_buffer(dev->first, dev->src_nents, +- dev->addr_vir, count, +- dev->total - dev->left_bytes)) { +- dev_err(dev->dev, "[%s:%d] pcopy err\n", +- __func__, __LINE__); +- return -EINVAL; +- } +- dev->left_bytes -= count; +- sg_init_one(&dev->sg_tmp, dev->addr_vir, count); +- if (!dma_map_sg(dev->dev, &dev->sg_tmp, 1, DMA_TO_DEVICE)) { +- dev_err(dev->dev, "[%s:%d] dma_map_sg(sg_tmp) error\n", +- __func__, __LINE__); +- return -ENOMEM; +- } +- dev->addr_in = sg_dma_address(&dev->sg_tmp); ++static const struct rk_variant rk3399_variant = { ++ .num_clks = 3, ++}; ++ ++static int rk_crypto_get_clks(struct rk_crypto_info *dev) ++{ ++ int i, j, err; ++ unsigned long cr; + +- if (sg_dst) { +- if (!dma_map_sg(dev->dev, &dev->sg_tmp, 1, +- DMA_FROM_DEVICE)) { +- dev_err(dev->dev, +- "[%s:%d] dma_map_sg(sg_tmp) error\n", +- __func__, __LINE__); +- dma_unmap_sg(dev->dev, &dev->sg_tmp, 1, +- DMA_TO_DEVICE); +- return -ENOMEM; ++ dev->num_clks = devm_clk_bulk_get_all(dev->dev, &dev->clks); ++ if (dev->num_clks < dev->variant->num_clks) { ++ dev_err(dev->dev, "Missing clocks, got %d instead of %d\n", ++ dev->num_clks, dev->variant->num_clks); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < dev->num_clks; i++) { ++ cr = clk_get_rate(dev->clks[i].clk); ++ for (j = 0; j < ARRAY_SIZE(dev->variant->rkclks); j++) { ++ if (dev->variant->rkclks[j].max == 0) ++ continue; ++ if (strcmp(dev->variant->rkclks[j].name, dev->clks[i].id)) ++ continue; ++ if (cr > dev->variant->rkclks[j].max) { ++ err = clk_set_rate(dev->clks[i].clk, ++ dev->variant->rkclks[j].max); ++ if (err) ++ dev_err(dev->dev, "Fail downclocking %s from %lu to %lu\n", ++ dev->variant->rkclks[j].name, cr, ++ dev->variant->rkclks[j].max); ++ else ++ dev_info(dev->dev, "Downclocking %s from %lu to %lu\n", ++ dev->variant->rkclks[j].name, cr, ++ dev->variant->rkclks[j].max); + } +- dev->addr_out = sg_dma_address(&dev->sg_tmp); + } + } +- dev->count = count; + return 0; + } + +-static void rk_unload_data(struct rk_crypto_info *dev) ++static int rk_crypto_enable_clk(struct rk_crypto_info *dev) + { +- struct scatterlist *sg_in, *sg_out; ++ int err; + +- sg_in = dev->aligned ? dev->sg_src : &dev->sg_tmp; +- dma_unmap_sg(dev->dev, sg_in, 1, DMA_TO_DEVICE); ++ err = clk_bulk_prepare_enable(dev->num_clks, dev->clks); ++ if (err) ++ dev_err(dev->dev, "Could not enable clock clks\n"); + +- if (dev->sg_dst) { +- sg_out = dev->aligned ? dev->sg_dst : &dev->sg_tmp; +- dma_unmap_sg(dev->dev, sg_out, 1, DMA_FROM_DEVICE); +- } ++ return err; + } + +-static irqreturn_t rk_crypto_irq_handle(int irq, void *dev_id) ++static void rk_crypto_disable_clk(struct rk_crypto_info *dev) + { +- struct rk_crypto_info *dev = platform_get_drvdata(dev_id); +- u32 interrupt_status; ++ clk_bulk_disable_unprepare(dev->num_clks, dev->clks); ++} + +- spin_lock(&dev->lock); +- interrupt_status = CRYPTO_READ(dev, RK_CRYPTO_INTSTS); +- CRYPTO_WRITE(dev, RK_CRYPTO_INTSTS, interrupt_status); ++/* ++ * Power management strategy: The device is suspended until a request ++ * is handled. For avoiding suspend/resume yoyo, the autosuspend is set to 2s. ++ */ ++static int rk_crypto_pm_suspend(struct device *dev) ++{ ++ struct rk_crypto_info *rkdev = dev_get_drvdata(dev); + +- if (interrupt_status & 0x0a) { +- dev_warn(dev->dev, "DMA Error\n"); +- dev->err = -EFAULT; +- } +- tasklet_schedule(&dev->done_task); ++ rk_crypto_disable_clk(rkdev); ++ reset_control_assert(rkdev->rst); + +- spin_unlock(&dev->lock); +- return IRQ_HANDLED; ++ return 0; + } + +-static int rk_crypto_enqueue(struct rk_crypto_info *dev, +- struct crypto_async_request *async_req) ++static int rk_crypto_pm_resume(struct device *dev) + { +- unsigned long flags; ++ struct rk_crypto_info *rkdev = dev_get_drvdata(dev); + int ret; + +- spin_lock_irqsave(&dev->lock, flags); +- ret = crypto_enqueue_request(&dev->queue, async_req); +- if (dev->busy) { +- spin_unlock_irqrestore(&dev->lock, flags); ++ ret = rk_crypto_enable_clk(rkdev); ++ if (ret) + return ret; +- } +- dev->busy = true; +- spin_unlock_irqrestore(&dev->lock, flags); +- tasklet_schedule(&dev->queue_task); + +- return ret; +-} ++ reset_control_deassert(rkdev->rst); ++ return 0; + +-static void rk_crypto_queue_task_cb(unsigned long data) +-{ +- struct rk_crypto_info *dev = (struct rk_crypto_info *)data; +- struct crypto_async_request *async_req, *backlog; +- unsigned long flags; +- int err = 0; ++} + +- dev->err = 0; +- spin_lock_irqsave(&dev->lock, flags); +- backlog = crypto_get_backlog(&dev->queue); +- async_req = crypto_dequeue_request(&dev->queue); ++static const struct dev_pm_ops rk_crypto_pm_ops = { ++ SET_RUNTIME_PM_OPS(rk_crypto_pm_suspend, rk_crypto_pm_resume, NULL) ++}; + +- if (!async_req) { +- dev->busy = false; +- spin_unlock_irqrestore(&dev->lock, flags); +- return; +- } +- spin_unlock_irqrestore(&dev->lock, flags); ++static int rk_crypto_pm_init(struct rk_crypto_info *rkdev) ++{ ++ int err; + +- if (backlog) { +- backlog->complete(backlog, -EINPROGRESS); +- backlog = NULL; +- } ++ pm_runtime_use_autosuspend(rkdev->dev); ++ pm_runtime_set_autosuspend_delay(rkdev->dev, 2000); + +- dev->async_req = async_req; +- err = dev->start(dev); ++ err = pm_runtime_set_suspended(rkdev->dev); + if (err) +- dev->complete(dev->async_req, err); ++ return err; ++ pm_runtime_enable(rkdev->dev); ++ return err; + } + +-static void rk_crypto_done_task_cb(unsigned long data) ++static void rk_crypto_pm_exit(struct rk_crypto_info *rkdev) ++{ ++ pm_runtime_disable(rkdev->dev); ++} ++ ++static irqreturn_t rk_crypto_irq_handle(int irq, void *dev_id) + { +- struct rk_crypto_info *dev = (struct rk_crypto_info *)data; ++ struct rk_crypto_info *dev = platform_get_drvdata(dev_id); ++ u32 interrupt_status; ++ ++ interrupt_status = CRYPTO_READ(dev, RK_CRYPTO_INTSTS); ++ CRYPTO_WRITE(dev, RK_CRYPTO_INTSTS, interrupt_status); + +- if (dev->err) { +- dev->complete(dev->async_req, dev->err); +- return; ++ dev->status = 1; ++ if (interrupt_status & 0x0a) { ++ dev_warn(dev->dev, "DMA Error\n"); ++ dev->status = 0; + } ++ complete(&dev->complete); + +- dev->err = dev->update(dev); +- if (dev->err) +- dev->complete(dev->async_req, dev->err); ++ return IRQ_HANDLED; + } + + static struct rk_crypto_tmp *rk_cipher_algs[] = { +@@ -257,6 +184,62 @@ static struct rk_crypto_tmp *rk_cipher_a + &rk_ahash_md5, + }; + ++#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG ++static int rk_crypto_debugfs_show(struct seq_file *seq, void *v) ++{ ++ struct rk_crypto_info *dd; ++ unsigned int i; ++ ++ spin_lock(&rocklist.lock); ++ list_for_each_entry(dd, &rocklist.dev_list, list) { ++ seq_printf(seq, "%s %s requests: %lu\n", ++ dev_driver_string(dd->dev), dev_name(dd->dev), ++ dd->nreq); ++ } ++ spin_unlock(&rocklist.lock); ++ ++ for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) { ++ if (!rk_cipher_algs[i]->dev) ++ continue; ++ switch (rk_cipher_algs[i]->type) { ++ case CRYPTO_ALG_TYPE_SKCIPHER: ++ seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n", ++ rk_cipher_algs[i]->alg.skcipher.base.cra_driver_name, ++ rk_cipher_algs[i]->alg.skcipher.base.cra_name, ++ rk_cipher_algs[i]->stat_req, rk_cipher_algs[i]->stat_fb); ++ seq_printf(seq, "\tfallback due to length: %lu\n", ++ rk_cipher_algs[i]->stat_fb_len); ++ seq_printf(seq, "\tfallback due to alignment: %lu\n", ++ rk_cipher_algs[i]->stat_fb_align); ++ seq_printf(seq, "\tfallback due to SGs: %lu\n", ++ rk_cipher_algs[i]->stat_fb_sgdiff); ++ break; ++ case CRYPTO_ALG_TYPE_AHASH: ++ seq_printf(seq, "%s %s reqs=%lu fallback=%lu\n", ++ rk_cipher_algs[i]->alg.hash.halg.base.cra_driver_name, ++ rk_cipher_algs[i]->alg.hash.halg.base.cra_name, ++ rk_cipher_algs[i]->stat_req, rk_cipher_algs[i]->stat_fb); ++ break; ++ } ++ } ++ return 0; ++} ++ ++DEFINE_SHOW_ATTRIBUTE(rk_crypto_debugfs); ++#endif ++ ++static void register_debugfs(struct rk_crypto_info *crypto_info) ++{ ++#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG ++ /* Ignore error of debugfs */ ++ rocklist.dbgfs_dir = debugfs_create_dir("rk3288_crypto", NULL); ++ rocklist.dbgfs_stats = debugfs_create_file("stats", 0444, ++ rocklist.dbgfs_dir, ++ &rocklist, ++ &rk_crypto_debugfs_fops); ++#endif ++} ++ + static int rk_crypto_register(struct rk_crypto_info *crypto_info) + { + unsigned int i, k; +@@ -264,12 +247,22 @@ static int rk_crypto_register(struct rk_ + + for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) { + rk_cipher_algs[i]->dev = crypto_info; +- if (rk_cipher_algs[i]->type == ALG_TYPE_CIPHER) +- err = crypto_register_skcipher( +- &rk_cipher_algs[i]->alg.skcipher); +- else +- err = crypto_register_ahash( +- &rk_cipher_algs[i]->alg.hash); ++ switch (rk_cipher_algs[i]->type) { ++ case CRYPTO_ALG_TYPE_SKCIPHER: ++ dev_info(crypto_info->dev, "Register %s as %s\n", ++ rk_cipher_algs[i]->alg.skcipher.base.cra_name, ++ rk_cipher_algs[i]->alg.skcipher.base.cra_driver_name); ++ err = crypto_register_skcipher(&rk_cipher_algs[i]->alg.skcipher); ++ break; ++ case CRYPTO_ALG_TYPE_AHASH: ++ dev_info(crypto_info->dev, "Register %s as %s\n", ++ rk_cipher_algs[i]->alg.hash.halg.base.cra_name, ++ rk_cipher_algs[i]->alg.hash.halg.base.cra_driver_name); ++ err = crypto_register_ahash(&rk_cipher_algs[i]->alg.hash); ++ break; ++ default: ++ dev_err(crypto_info->dev, "unknown algorithm\n"); ++ } + if (err) + goto err_cipher_algs; + } +@@ -277,7 +270,7 @@ static int rk_crypto_register(struct rk_ + + err_cipher_algs: + for (k = 0; k < i; k++) { +- if (rk_cipher_algs[i]->type == ALG_TYPE_CIPHER) ++ if (rk_cipher_algs[i]->type == CRYPTO_ALG_TYPE_SKCIPHER) + crypto_unregister_skcipher(&rk_cipher_algs[k]->alg.skcipher); + else + crypto_unregister_ahash(&rk_cipher_algs[i]->alg.hash); +@@ -290,22 +283,23 @@ static void rk_crypto_unregister(void) + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(rk_cipher_algs); i++) { +- if (rk_cipher_algs[i]->type == ALG_TYPE_CIPHER) ++ if (rk_cipher_algs[i]->type == CRYPTO_ALG_TYPE_SKCIPHER) + crypto_unregister_skcipher(&rk_cipher_algs[i]->alg.skcipher); + else + crypto_unregister_ahash(&rk_cipher_algs[i]->alg.hash); + } + } + +-static void rk_crypto_action(void *data) +-{ +- struct rk_crypto_info *crypto_info = data; +- +- reset_control_assert(crypto_info->rst); +-} +- + static const struct of_device_id crypto_of_id_table[] = { +- { .compatible = "rockchip,rk3288-crypto" }, ++ { .compatible = "rockchip,rk3288-crypto", ++ .data = &rk3288_variant, ++ }, ++ { .compatible = "rockchip,rk3328-crypto", ++ .data = &rk3328_variant, ++ }, ++ { .compatible = "rockchip,rk3399-crypto", ++ .data = &rk3399_variant, ++ }, + {} + }; + MODULE_DEVICE_TABLE(of, crypto_of_id_table); +@@ -313,7 +307,7 @@ MODULE_DEVICE_TABLE(of, crypto_of_id_tab + static int rk_crypto_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +- struct rk_crypto_info *crypto_info; ++ struct rk_crypto_info *crypto_info, *first; + int err = 0; + + crypto_info = devm_kzalloc(&pdev->dev, +@@ -323,7 +317,16 @@ static int rk_crypto_probe(struct platfo + goto err_crypto; + } + +- crypto_info->rst = devm_reset_control_get(dev, "crypto-rst"); ++ crypto_info->dev = &pdev->dev; ++ platform_set_drvdata(pdev, crypto_info); ++ ++ crypto_info->variant = of_device_get_match_data(&pdev->dev); ++ if (!crypto_info->variant) { ++ dev_err(&pdev->dev, "Missing variant\n"); ++ return -EINVAL; ++ } ++ ++ crypto_info->rst = devm_reset_control_array_get_exclusive(dev); + if (IS_ERR(crypto_info->rst)) { + err = PTR_ERR(crypto_info->rst); + goto err_crypto; +@@ -333,46 +336,19 @@ static int rk_crypto_probe(struct platfo + usleep_range(10, 20); + reset_control_deassert(crypto_info->rst); + +- err = devm_add_action_or_reset(dev, rk_crypto_action, crypto_info); +- if (err) +- goto err_crypto; +- +- spin_lock_init(&crypto_info->lock); +- + crypto_info->reg = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(crypto_info->reg)) { + err = PTR_ERR(crypto_info->reg); + goto err_crypto; + } + +- crypto_info->aclk = devm_clk_get(&pdev->dev, "aclk"); +- if (IS_ERR(crypto_info->aclk)) { +- err = PTR_ERR(crypto_info->aclk); +- goto err_crypto; +- } +- +- crypto_info->hclk = devm_clk_get(&pdev->dev, "hclk"); +- if (IS_ERR(crypto_info->hclk)) { +- err = PTR_ERR(crypto_info->hclk); +- goto err_crypto; +- } +- +- crypto_info->sclk = devm_clk_get(&pdev->dev, "sclk"); +- if (IS_ERR(crypto_info->sclk)) { +- err = PTR_ERR(crypto_info->sclk); +- goto err_crypto; +- } +- +- crypto_info->dmaclk = devm_clk_get(&pdev->dev, "apb_pclk"); +- if (IS_ERR(crypto_info->dmaclk)) { +- err = PTR_ERR(crypto_info->dmaclk); ++ err = rk_crypto_get_clks(crypto_info); ++ if (err) + goto err_crypto; +- } + + crypto_info->irq = platform_get_irq(pdev, 0); + if (crypto_info->irq < 0) { +- dev_warn(crypto_info->dev, +- "control Interrupt is not available.\n"); ++ dev_err(&pdev->dev, "control Interrupt is not available.\n"); + err = crypto_info->irq; + goto err_crypto; + } +@@ -382,49 +358,64 @@ static int rk_crypto_probe(struct platfo + "rk-crypto", pdev); + + if (err) { +- dev_err(crypto_info->dev, "irq request failed.\n"); ++ dev_err(&pdev->dev, "irq request failed.\n"); + goto err_crypto; + } + +- crypto_info->dev = &pdev->dev; +- platform_set_drvdata(pdev, crypto_info); ++ crypto_info->engine = crypto_engine_alloc_init(&pdev->dev, true); ++ crypto_engine_start(crypto_info->engine); ++ init_completion(&crypto_info->complete); + +- tasklet_init(&crypto_info->queue_task, +- rk_crypto_queue_task_cb, (unsigned long)crypto_info); +- tasklet_init(&crypto_info->done_task, +- rk_crypto_done_task_cb, (unsigned long)crypto_info); +- crypto_init_queue(&crypto_info->queue, 50); +- +- crypto_info->enable_clk = rk_crypto_enable_clk; +- crypto_info->disable_clk = rk_crypto_disable_clk; +- crypto_info->load_data = rk_load_data; +- crypto_info->unload_data = rk_unload_data; +- crypto_info->enqueue = rk_crypto_enqueue; +- crypto_info->busy = false; ++ err = rk_crypto_pm_init(crypto_info); ++ if (err) ++ goto err_pm; + +- err = rk_crypto_register(crypto_info); +- if (err) { +- dev_err(dev, "err in register alg"); +- goto err_register_alg; ++ spin_lock(&rocklist.lock); ++ first = list_first_entry_or_null(&rocklist.dev_list, ++ struct rk_crypto_info, list); ++ list_add_tail(&crypto_info->list, &rocklist.dev_list); ++ spin_unlock(&rocklist.lock); ++ ++ if (!first) { ++ err = rk_crypto_register(crypto_info); ++ if (err) { ++ dev_err(dev, "Fail to register crypto algorithms"); ++ goto err_register_alg; ++ } ++ ++ register_debugfs(crypto_info); + } + +- dev_info(dev, "Crypto Accelerator successfully registered\n"); + return 0; + + err_register_alg: +- tasklet_kill(&crypto_info->queue_task); +- tasklet_kill(&crypto_info->done_task); ++ rk_crypto_pm_exit(crypto_info); ++err_pm: ++ crypto_engine_exit(crypto_info->engine); + err_crypto: ++ dev_err(dev, "Crypto Accelerator not successfully registered\n"); + return err; + } + + static int rk_crypto_remove(struct platform_device *pdev) + { + struct rk_crypto_info *crypto_tmp = platform_get_drvdata(pdev); ++ struct rk_crypto_info *first; + +- rk_crypto_unregister(); +- tasklet_kill(&crypto_tmp->done_task); +- tasklet_kill(&crypto_tmp->queue_task); ++ spin_lock_bh(&rocklist.lock); ++ list_del(&crypto_tmp->list); ++ first = list_first_entry_or_null(&rocklist.dev_list, ++ struct rk_crypto_info, list); ++ spin_unlock_bh(&rocklist.lock); ++ ++ if (!first) { ++#ifdef CONFIG_CRYPTO_DEV_ROCKCHIP_DEBUG ++ debugfs_remove_recursive(rocklist.dbgfs_dir); ++#endif ++ rk_crypto_unregister(); ++ } ++ rk_crypto_pm_exit(crypto_tmp); ++ crypto_engine_exit(crypto_tmp->engine); + return 0; + } + +@@ -433,6 +424,7 @@ static struct platform_driver crypto_dri + .remove = rk_crypto_remove, + .driver = { + .name = "rk3288-crypto", ++ .pm = &rk_crypto_pm_ops, + .of_match_table = crypto_of_id_table, + }, + }; +--- a/drivers/crypto/rockchip/rk3288_crypto.h ++++ b/drivers/crypto/rockchip/rk3288_crypto.h +@@ -5,9 +5,13 @@ + #include + #include + #include ++#include + #include ++#include + #include ++#include + #include ++#include + #include + #include + +@@ -184,85 +188,91 @@ + #define CRYPTO_WRITE(dev, offset, val) \ + writel_relaxed((val), ((dev)->reg + (offset))) + ++#define RK_MAX_CLKS 4 ++ ++/* ++ * struct rockchip_ip - struct for managing a list of RK crypto instance ++ * @dev_list: Used for doing a list of rk_crypto_info ++ * @lock: Control access to dev_list ++ * @dbgfs_dir: Debugfs dentry for statistic directory ++ * @dbgfs_stats: Debugfs dentry for statistic counters ++ */ ++struct rockchip_ip { ++ struct list_head dev_list; ++ spinlock_t lock; /* Control access to dev_list */ ++ struct dentry *dbgfs_dir; ++ struct dentry *dbgfs_stats; ++}; ++ ++struct rk_clks { ++ const char *name; ++ unsigned long max; ++}; ++ ++struct rk_variant { ++ int num_clks; ++ struct rk_clks rkclks[RK_MAX_CLKS]; ++}; ++ + struct rk_crypto_info { ++ struct list_head list; + struct device *dev; +- struct clk *aclk; +- struct clk *hclk; +- struct clk *sclk; +- struct clk *dmaclk; ++ struct clk_bulk_data *clks; ++ int num_clks; + struct reset_control *rst; + void __iomem *reg; + int irq; +- struct crypto_queue queue; +- struct tasklet_struct queue_task; +- struct tasklet_struct done_task; +- struct crypto_async_request *async_req; +- int err; +- /* device lock */ +- spinlock_t lock; +- +- /* the public variable */ +- struct scatterlist *sg_src; +- struct scatterlist *sg_dst; +- struct scatterlist sg_tmp; +- struct scatterlist *first; +- unsigned int left_bytes; +- void *addr_vir; +- int aligned; +- int align_size; +- size_t src_nents; +- size_t dst_nents; +- unsigned int total; +- unsigned int count; +- dma_addr_t addr_in; +- dma_addr_t addr_out; +- bool busy; +- int (*start)(struct rk_crypto_info *dev); +- int (*update)(struct rk_crypto_info *dev); +- void (*complete)(struct crypto_async_request *base, int err); +- int (*enable_clk)(struct rk_crypto_info *dev); +- void (*disable_clk)(struct rk_crypto_info *dev); +- int (*load_data)(struct rk_crypto_info *dev, +- struct scatterlist *sg_src, +- struct scatterlist *sg_dst); +- void (*unload_data)(struct rk_crypto_info *dev); +- int (*enqueue)(struct rk_crypto_info *dev, +- struct crypto_async_request *async_req); ++ const struct rk_variant *variant; ++ unsigned long nreq; ++ struct crypto_engine *engine; ++ struct completion complete; ++ int status; + }; + + /* the private variable of hash */ + struct rk_ahash_ctx { +- struct rk_crypto_info *dev; ++ struct crypto_engine_ctx enginectx; + /* for fallback */ + struct crypto_ahash *fallback_tfm; + }; + +-/* the privete variable of hash for fallback */ ++/* the private variable of hash for fallback */ + struct rk_ahash_rctx { ++ struct rk_crypto_info *dev; + struct ahash_request fallback_req; + u32 mode; ++ int nrsg; + }; + + /* the private variable of cipher */ + struct rk_cipher_ctx { +- struct rk_crypto_info *dev; ++ struct crypto_engine_ctx enginectx; + unsigned int keylen; +- u32 mode; ++ u8 key[AES_MAX_KEY_SIZE]; + u8 iv[AES_BLOCK_SIZE]; ++ struct crypto_skcipher *fallback_tfm; + }; + +-enum alg_type { +- ALG_TYPE_HASH, +- ALG_TYPE_CIPHER, ++struct rk_cipher_rctx { ++ struct rk_crypto_info *dev; ++ u8 backup_iv[AES_BLOCK_SIZE]; ++ u32 mode; ++ struct skcipher_request fallback_req; // keep at the end + }; + + struct rk_crypto_tmp { +- struct rk_crypto_info *dev; ++ u32 type; ++ struct rk_crypto_info *dev; + union { + struct skcipher_alg skcipher; + struct ahash_alg hash; + } alg; +- enum alg_type type; ++ unsigned long stat_req; ++ unsigned long stat_fb; ++ unsigned long stat_fb_len; ++ unsigned long stat_fb_sglen; ++ unsigned long stat_fb_align; ++ unsigned long stat_fb_sgdiff; + }; + + extern struct rk_crypto_tmp rk_ecb_aes_alg; +@@ -276,4 +286,5 @@ extern struct rk_crypto_tmp rk_ahash_sha + extern struct rk_crypto_tmp rk_ahash_sha256; + extern struct rk_crypto_tmp rk_ahash_md5; + ++struct rk_crypto_info *get_rk_crypto(void); + #endif +--- a/drivers/crypto/rockchip/rk3288_crypto_ahash.c ++++ b/drivers/crypto/rockchip/rk3288_crypto_ahash.c +@@ -9,6 +9,8 @@ + * Some ideas are from marvell/cesa.c and s5p-sss.c driver. + */ + #include ++#include ++#include + #include "rk3288_crypto.h" + + /* +@@ -16,6 +18,44 @@ + * so we put the fixed hash out when met zero message. + */ + ++static bool rk_ahash_need_fallback(struct ahash_request *req) ++{ ++ struct scatterlist *sg; ++ ++ sg = req->src; ++ while (sg) { ++ if (!IS_ALIGNED(sg->offset, sizeof(u32))) { ++ return true; ++ } ++ if (sg->length % 4) { ++ return true; ++ } ++ sg = sg_next(sg); ++ } ++ return false; ++} ++ ++static int rk_ahash_digest_fb(struct ahash_request *areq) ++{ ++ struct rk_ahash_rctx *rctx = ahash_request_ctx(areq); ++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); ++ struct rk_ahash_ctx *tfmctx = crypto_ahash_ctx(tfm); ++ struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg); ++ struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.hash); ++ ++ algt->stat_fb++; ++ ++ ahash_request_set_tfm(&rctx->fallback_req, tfmctx->fallback_tfm); ++ rctx->fallback_req.base.flags = areq->base.flags & ++ CRYPTO_TFM_REQ_MAY_SLEEP; ++ ++ rctx->fallback_req.nbytes = areq->nbytes; ++ rctx->fallback_req.src = areq->src; ++ rctx->fallback_req.result = areq->result; ++ ++ return crypto_ahash_digest(&rctx->fallback_req); ++} ++ + static int zero_message_process(struct ahash_request *req) + { + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); +@@ -38,15 +78,9 @@ static int zero_message_process(struct a + return 0; + } + +-static void rk_ahash_crypto_complete(struct crypto_async_request *base, int err) +-{ +- if (base->complete) +- base->complete(base, err); +-} +- +-static void rk_ahash_reg_init(struct rk_crypto_info *dev) ++static void rk_ahash_reg_init(struct ahash_request *req, ++ struct rk_crypto_info *dev) + { +- struct ahash_request *req = ahash_request_cast(dev->async_req); + struct rk_ahash_rctx *rctx = ahash_request_ctx(req); + int reg_status; + +@@ -74,7 +108,7 @@ static void rk_ahash_reg_init(struct rk_ + RK_CRYPTO_BYTESWAP_BRFIFO | + RK_CRYPTO_BYTESWAP_BTFIFO); + +- CRYPTO_WRITE(dev, RK_CRYPTO_HASH_MSG_LEN, dev->total); ++ CRYPTO_WRITE(dev, RK_CRYPTO_HASH_MSG_LEN, req->nbytes); + } + + static int rk_ahash_init(struct ahash_request *req) +@@ -164,51 +198,80 @@ static int rk_ahash_export(struct ahash_ + + static int rk_ahash_digest(struct ahash_request *req) + { +- struct rk_ahash_ctx *tctx = crypto_tfm_ctx(req->base.tfm); +- struct rk_crypto_info *dev = tctx->dev; ++ struct rk_ahash_rctx *rctx = ahash_request_ctx(req); ++ struct rk_crypto_info *dev; ++ struct crypto_engine *engine; ++ ++ if (rk_ahash_need_fallback(req)) ++ return rk_ahash_digest_fb(req); + + if (!req->nbytes) + return zero_message_process(req); +- else +- return dev->enqueue(dev, &req->base); ++ ++ dev = get_rk_crypto(); ++ ++ rctx->dev = dev; ++ engine = dev->engine; ++ ++ return crypto_transfer_hash_request_to_engine(engine, req); + } + +-static void crypto_ahash_dma_start(struct rk_crypto_info *dev) ++static void crypto_ahash_dma_start(struct rk_crypto_info *dev, struct scatterlist *sg) + { +- CRYPTO_WRITE(dev, RK_CRYPTO_HRDMAS, dev->addr_in); +- CRYPTO_WRITE(dev, RK_CRYPTO_HRDMAL, (dev->count + 3) / 4); ++ CRYPTO_WRITE(dev, RK_CRYPTO_HRDMAS, sg_dma_address(sg)); ++ CRYPTO_WRITE(dev, RK_CRYPTO_HRDMAL, sg_dma_len(sg) / 4); + CRYPTO_WRITE(dev, RK_CRYPTO_CTRL, RK_CRYPTO_HASH_START | + (RK_CRYPTO_HASH_START << 16)); + } + +-static int rk_ahash_set_data_start(struct rk_crypto_info *dev) ++static int rk_hash_prepare(struct crypto_engine *engine, void *breq) ++{ ++ struct ahash_request *areq = container_of(breq, struct ahash_request, base); ++ struct rk_ahash_rctx *rctx = ahash_request_ctx(areq); ++ struct rk_crypto_info *rkc = rctx->dev; ++ int ret; ++ ++ ret = dma_map_sg(rkc->dev, areq->src, sg_nents(areq->src), DMA_TO_DEVICE); ++ if (ret <= 0) ++ return -EINVAL; ++ ++ rctx->nrsg = ret; ++ ++ return 0; ++} ++ ++static int rk_hash_unprepare(struct crypto_engine *engine, void *breq) ++{ ++ struct ahash_request *areq = container_of(breq, struct ahash_request, base); ++ struct rk_ahash_rctx *rctx = ahash_request_ctx(areq); ++ struct rk_crypto_info *rkc = rctx->dev; ++ ++ dma_unmap_sg(rkc->dev, areq->src, rctx->nrsg, DMA_TO_DEVICE); ++ return 0; ++} ++ ++static int rk_hash_run(struct crypto_engine *engine, void *breq) + { +- int err; ++ struct ahash_request *areq = container_of(breq, struct ahash_request, base); ++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq); ++ struct rk_ahash_rctx *rctx = ahash_request_ctx(areq); ++ struct ahash_alg *alg = __crypto_ahash_alg(tfm->base.__crt_alg); ++ struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.hash); ++ struct scatterlist *sg = areq->src; ++ struct rk_crypto_info *rkc = rctx->dev; ++ int err = 0; ++ int i; ++ u32 v; ++ ++ err = pm_runtime_resume_and_get(rkc->dev); ++ if (err) ++ return err; + +- err = dev->load_data(dev, dev->sg_src, NULL); +- if (!err) +- crypto_ahash_dma_start(dev); +- return err; +-} +- +-static int rk_ahash_start(struct rk_crypto_info *dev) +-{ +- struct ahash_request *req = ahash_request_cast(dev->async_req); +- struct crypto_ahash *tfm; +- struct rk_ahash_rctx *rctx; +- +- dev->total = req->nbytes; +- dev->left_bytes = req->nbytes; +- dev->aligned = 0; +- dev->align_size = 4; +- dev->sg_dst = NULL; +- dev->sg_src = req->src; +- dev->first = req->src; +- dev->src_nents = sg_nents(req->src); +- rctx = ahash_request_ctx(req); + rctx->mode = 0; + +- tfm = crypto_ahash_reqtfm(req); ++ algt->stat_req++; ++ rkc->nreq++; ++ + switch (crypto_ahash_digestsize(tfm)) { + case SHA1_DIGEST_SIZE: + rctx->mode = RK_CRYPTO_HASH_SHA1; +@@ -220,100 +283,88 @@ static int rk_ahash_start(struct rk_cryp + rctx->mode = RK_CRYPTO_HASH_MD5; + break; + default: +- return -EINVAL; ++ err = -EINVAL; ++ goto theend; + } + +- rk_ahash_reg_init(dev); +- return rk_ahash_set_data_start(dev); +-} +- +-static int rk_ahash_crypto_rx(struct rk_crypto_info *dev) +-{ +- int err = 0; +- struct ahash_request *req = ahash_request_cast(dev->async_req); +- struct crypto_ahash *tfm; ++ rk_ahash_reg_init(areq, rkc); + +- dev->unload_data(dev); +- if (dev->left_bytes) { +- if (dev->aligned) { +- if (sg_is_last(dev->sg_src)) { +- dev_warn(dev->dev, "[%s:%d], Lack of data\n", +- __func__, __LINE__); +- err = -ENOMEM; +- goto out_rx; +- } +- dev->sg_src = sg_next(dev->sg_src); ++ while (sg) { ++ reinit_completion(&rkc->complete); ++ rkc->status = 0; ++ crypto_ahash_dma_start(rkc, sg); ++ wait_for_completion_interruptible_timeout(&rkc->complete, ++ msecs_to_jiffies(2000)); ++ if (!rkc->status) { ++ dev_err(rkc->dev, "DMA timeout\n"); ++ err = -EFAULT; ++ goto theend; + } +- err = rk_ahash_set_data_start(dev); +- } else { +- /* +- * it will take some time to process date after last dma +- * transmission. +- * +- * waiting time is relative with the last date len, +- * so cannot set a fixed time here. +- * 10us makes system not call here frequently wasting +- * efficiency, and make it response quickly when dma +- * complete. +- */ +- while (!CRYPTO_READ(dev, RK_CRYPTO_HASH_STS)) +- udelay(10); +- +- tfm = crypto_ahash_reqtfm(req); +- memcpy_fromio(req->result, dev->reg + RK_CRYPTO_HASH_DOUT_0, +- crypto_ahash_digestsize(tfm)); +- dev->complete(dev->async_req, 0); +- tasklet_schedule(&dev->queue_task); ++ sg = sg_next(sg); ++ } ++ ++ /* ++ * it will take some time to process date after last dma ++ * transmission. ++ * ++ * waiting time is relative with the last date len, ++ * so cannot set a fixed time here. ++ * 10us makes system not call here frequently wasting ++ * efficiency, and make it response quickly when dma ++ * complete. ++ */ ++ readl_poll_timeout(rkc->reg + RK_CRYPTO_HASH_STS, v, v == 0, 10, 1000); ++ ++ for (i = 0; i < crypto_ahash_digestsize(tfm) / 4; i++) { ++ v = readl(rkc->reg + RK_CRYPTO_HASH_DOUT_0 + i * 4); ++ put_unaligned_le32(v, areq->result + i * 4); + } + +-out_rx: +- return err; ++theend: ++ pm_runtime_put_autosuspend(rkc->dev); ++ ++ local_bh_disable(); ++ crypto_finalize_hash_request(engine, breq, err); ++ local_bh_enable(); ++ ++ return 0; + } + + static int rk_cra_hash_init(struct crypto_tfm *tfm) + { + struct rk_ahash_ctx *tctx = crypto_tfm_ctx(tfm); +- struct rk_crypto_tmp *algt; +- struct ahash_alg *alg = __crypto_ahash_alg(tfm->__crt_alg); +- + const char *alg_name = crypto_tfm_alg_name(tfm); +- +- algt = container_of(alg, struct rk_crypto_tmp, alg.hash); +- +- tctx->dev = algt->dev; +- tctx->dev->addr_vir = (void *)__get_free_page(GFP_KERNEL); +- if (!tctx->dev->addr_vir) { +- dev_err(tctx->dev->dev, "failed to kmalloc for addr_vir\n"); +- return -ENOMEM; +- } +- tctx->dev->start = rk_ahash_start; +- tctx->dev->update = rk_ahash_crypto_rx; +- tctx->dev->complete = rk_ahash_crypto_complete; ++ struct ahash_alg *alg = __crypto_ahash_alg(tfm->__crt_alg); ++ struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.hash); + + /* for fallback */ + tctx->fallback_tfm = crypto_alloc_ahash(alg_name, 0, +- CRYPTO_ALG_NEED_FALLBACK); ++ CRYPTO_ALG_NEED_FALLBACK); + if (IS_ERR(tctx->fallback_tfm)) { +- dev_err(tctx->dev->dev, "Could not load fallback driver.\n"); ++ dev_err(algt->dev->dev, "Could not load fallback driver.\n"); + return PTR_ERR(tctx->fallback_tfm); + } ++ + crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), + sizeof(struct rk_ahash_rctx) + + crypto_ahash_reqsize(tctx->fallback_tfm)); + +- return tctx->dev->enable_clk(tctx->dev); ++ tctx->enginectx.op.do_one_request = rk_hash_run; ++ tctx->enginectx.op.prepare_request = rk_hash_prepare; ++ tctx->enginectx.op.unprepare_request = rk_hash_unprepare; ++ ++ return 0; + } + + static void rk_cra_hash_exit(struct crypto_tfm *tfm) + { + struct rk_ahash_ctx *tctx = crypto_tfm_ctx(tfm); + +- free_page((unsigned long)tctx->dev->addr_vir); +- return tctx->dev->disable_clk(tctx->dev); ++ crypto_free_ahash(tctx->fallback_tfm); + } + + struct rk_crypto_tmp rk_ahash_sha1 = { +- .type = ALG_TYPE_HASH, ++ .type = CRYPTO_ALG_TYPE_AHASH, + .alg.hash = { + .init = rk_ahash_init, + .update = rk_ahash_update, +@@ -337,13 +388,13 @@ struct rk_crypto_tmp rk_ahash_sha1 = { + .cra_init = rk_cra_hash_init, + .cra_exit = rk_cra_hash_exit, + .cra_module = THIS_MODULE, +- } +- } ++ } ++ } + } + }; + + struct rk_crypto_tmp rk_ahash_sha256 = { +- .type = ALG_TYPE_HASH, ++ .type = CRYPTO_ALG_TYPE_AHASH, + .alg.hash = { + .init = rk_ahash_init, + .update = rk_ahash_update, +@@ -367,13 +418,13 @@ struct rk_crypto_tmp rk_ahash_sha256 = { + .cra_init = rk_cra_hash_init, + .cra_exit = rk_cra_hash_exit, + .cra_module = THIS_MODULE, +- } +- } ++ } ++ } + } + }; + + struct rk_crypto_tmp rk_ahash_md5 = { +- .type = ALG_TYPE_HASH, ++ .type = CRYPTO_ALG_TYPE_AHASH, + .alg.hash = { + .init = rk_ahash_init, + .update = rk_ahash_update, +@@ -397,7 +448,7 @@ struct rk_crypto_tmp rk_ahash_md5 = { + .cra_init = rk_cra_hash_init, + .cra_exit = rk_cra_hash_exit, + .cra_module = THIS_MODULE, +- } + } ++ } + } + }; +--- a/drivers/crypto/rockchip/rk3288_crypto_skcipher.c ++++ b/drivers/crypto/rockchip/rk3288_crypto_skcipher.c +@@ -9,23 +9,94 @@ + * Some ideas are from marvell-cesa.c and s5p-sss.c driver. + */ + #include ++#include + #include "rk3288_crypto.h" + + #define RK_CRYPTO_DEC BIT(0) + +-static void rk_crypto_complete(struct crypto_async_request *base, int err) ++static int rk_cipher_need_fallback(struct skcipher_request *req) + { +- if (base->complete) +- base->complete(base, err); ++ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); ++ struct skcipher_alg *alg = crypto_skcipher_alg(tfm); ++ struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.skcipher); ++ struct scatterlist *sgs, *sgd; ++ unsigned int stodo, dtodo, len; ++ unsigned int bs = crypto_skcipher_blocksize(tfm); ++ ++ if (!req->cryptlen) ++ return true; ++ ++ len = req->cryptlen; ++ sgs = req->src; ++ sgd = req->dst; ++ while (sgs && sgd) { ++ if (!IS_ALIGNED(sgs->offset, sizeof(u32))) { ++ algt->stat_fb_align++; ++ return true; ++ } ++ if (!IS_ALIGNED(sgd->offset, sizeof(u32))) { ++ algt->stat_fb_align++; ++ return true; ++ } ++ stodo = min(len, sgs->length); ++ if (stodo % bs) { ++ algt->stat_fb_len++; ++ return true; ++ } ++ dtodo = min(len, sgd->length); ++ if (dtodo % bs) { ++ algt->stat_fb_len++; ++ return true; ++ } ++ if (stodo != dtodo) { ++ algt->stat_fb_sgdiff++; ++ return true; ++ } ++ len -= stodo; ++ sgs = sg_next(sgs); ++ sgd = sg_next(sgd); ++ } ++ return false; + } + +-static int rk_handle_req(struct rk_crypto_info *dev, +- struct skcipher_request *req) ++static int rk_cipher_fallback(struct skcipher_request *areq) + { +- if (!IS_ALIGNED(req->cryptlen, dev->align_size)) +- return -EINVAL; ++ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); ++ struct rk_cipher_ctx *op = crypto_skcipher_ctx(tfm); ++ struct rk_cipher_rctx *rctx = skcipher_request_ctx(areq); ++ struct skcipher_alg *alg = crypto_skcipher_alg(tfm); ++ struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.skcipher); ++ int err; ++ ++ algt->stat_fb++; ++ ++ skcipher_request_set_tfm(&rctx->fallback_req, op->fallback_tfm); ++ skcipher_request_set_callback(&rctx->fallback_req, areq->base.flags, ++ areq->base.complete, areq->base.data); ++ skcipher_request_set_crypt(&rctx->fallback_req, areq->src, areq->dst, ++ areq->cryptlen, areq->iv); ++ if (rctx->mode & RK_CRYPTO_DEC) ++ err = crypto_skcipher_decrypt(&rctx->fallback_req); + else +- return dev->enqueue(dev, &req->base); ++ err = crypto_skcipher_encrypt(&rctx->fallback_req); ++ return err; ++} ++ ++static int rk_cipher_handle_req(struct skcipher_request *req) ++{ ++ struct rk_cipher_rctx *rctx = skcipher_request_ctx(req); ++ struct rk_crypto_info *rkc; ++ struct crypto_engine *engine; ++ ++ if (rk_cipher_need_fallback(req)) ++ return rk_cipher_fallback(req); ++ ++ rkc = get_rk_crypto(); ++ ++ engine = rkc->engine; ++ rctx->dev = rkc; ++ ++ return crypto_transfer_skcipher_request_to_engine(engine, req); + } + + static int rk_aes_setkey(struct crypto_skcipher *cipher, +@@ -38,8 +109,9 @@ static int rk_aes_setkey(struct crypto_s + keylen != AES_KEYSIZE_256) + return -EINVAL; + ctx->keylen = keylen; +- memcpy_toio(ctx->dev->reg + RK_CRYPTO_AES_KEY_0, key, keylen); +- return 0; ++ memcpy(ctx->key, key, keylen); ++ ++ return crypto_skcipher_setkey(ctx->fallback_tfm, key, keylen); + } + + static int rk_des_setkey(struct crypto_skcipher *cipher, +@@ -53,8 +125,9 @@ static int rk_des_setkey(struct crypto_s + return err; + + ctx->keylen = keylen; +- memcpy_toio(ctx->dev->reg + RK_CRYPTO_TDES_KEY1_0, key, keylen); +- return 0; ++ memcpy(ctx->key, key, keylen); ++ ++ return crypto_skcipher_setkey(ctx->fallback_tfm, key, keylen); + } + + static int rk_tdes_setkey(struct crypto_skcipher *cipher, +@@ -68,161 +141,136 @@ static int rk_tdes_setkey(struct crypto_ + return err; + + ctx->keylen = keylen; +- memcpy_toio(ctx->dev->reg + RK_CRYPTO_TDES_KEY1_0, key, keylen); +- return 0; ++ memcpy(ctx->key, key, keylen); ++ ++ return crypto_skcipher_setkey(ctx->fallback_tfm, key, keylen); + } + + static int rk_aes_ecb_encrypt(struct skcipher_request *req) + { +- struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); +- struct rk_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); +- struct rk_crypto_info *dev = ctx->dev; ++ struct rk_cipher_rctx *rctx = skcipher_request_ctx(req); + +- ctx->mode = RK_CRYPTO_AES_ECB_MODE; +- return rk_handle_req(dev, req); ++ rctx->mode = RK_CRYPTO_AES_ECB_MODE; ++ return rk_cipher_handle_req(req); + } + + static int rk_aes_ecb_decrypt(struct skcipher_request *req) + { +- struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); +- struct rk_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); +- struct rk_crypto_info *dev = ctx->dev; ++ struct rk_cipher_rctx *rctx = skcipher_request_ctx(req); + +- ctx->mode = RK_CRYPTO_AES_ECB_MODE | RK_CRYPTO_DEC; +- return rk_handle_req(dev, req); ++ rctx->mode = RK_CRYPTO_AES_ECB_MODE | RK_CRYPTO_DEC; ++ return rk_cipher_handle_req(req); + } + + static int rk_aes_cbc_encrypt(struct skcipher_request *req) + { +- struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); +- struct rk_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); +- struct rk_crypto_info *dev = ctx->dev; ++ struct rk_cipher_rctx *rctx = skcipher_request_ctx(req); + +- ctx->mode = RK_CRYPTO_AES_CBC_MODE; +- return rk_handle_req(dev, req); ++ rctx->mode = RK_CRYPTO_AES_CBC_MODE; ++ return rk_cipher_handle_req(req); + } + + static int rk_aes_cbc_decrypt(struct skcipher_request *req) + { +- struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); +- struct rk_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); +- struct rk_crypto_info *dev = ctx->dev; ++ struct rk_cipher_rctx *rctx = skcipher_request_ctx(req); + +- ctx->mode = RK_CRYPTO_AES_CBC_MODE | RK_CRYPTO_DEC; +- return rk_handle_req(dev, req); ++ rctx->mode = RK_CRYPTO_AES_CBC_MODE | RK_CRYPTO_DEC; ++ return rk_cipher_handle_req(req); + } + + static int rk_des_ecb_encrypt(struct skcipher_request *req) + { +- struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); +- struct rk_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); +- struct rk_crypto_info *dev = ctx->dev; ++ struct rk_cipher_rctx *rctx = skcipher_request_ctx(req); + +- ctx->mode = 0; +- return rk_handle_req(dev, req); ++ rctx->mode = 0; ++ return rk_cipher_handle_req(req); + } + + static int rk_des_ecb_decrypt(struct skcipher_request *req) + { +- struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); +- struct rk_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); +- struct rk_crypto_info *dev = ctx->dev; ++ struct rk_cipher_rctx *rctx = skcipher_request_ctx(req); + +- ctx->mode = RK_CRYPTO_DEC; +- return rk_handle_req(dev, req); ++ rctx->mode = RK_CRYPTO_DEC; ++ return rk_cipher_handle_req(req); + } + + static int rk_des_cbc_encrypt(struct skcipher_request *req) + { +- struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); +- struct rk_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); +- struct rk_crypto_info *dev = ctx->dev; ++ struct rk_cipher_rctx *rctx = skcipher_request_ctx(req); + +- ctx->mode = RK_CRYPTO_TDES_CHAINMODE_CBC; +- return rk_handle_req(dev, req); ++ rctx->mode = RK_CRYPTO_TDES_CHAINMODE_CBC; ++ return rk_cipher_handle_req(req); + } + + static int rk_des_cbc_decrypt(struct skcipher_request *req) + { +- struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); +- struct rk_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); +- struct rk_crypto_info *dev = ctx->dev; ++ struct rk_cipher_rctx *rctx = skcipher_request_ctx(req); + +- ctx->mode = RK_CRYPTO_TDES_CHAINMODE_CBC | RK_CRYPTO_DEC; +- return rk_handle_req(dev, req); ++ rctx->mode = RK_CRYPTO_TDES_CHAINMODE_CBC | RK_CRYPTO_DEC; ++ return rk_cipher_handle_req(req); + } + + static int rk_des3_ede_ecb_encrypt(struct skcipher_request *req) + { +- struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); +- struct rk_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); +- struct rk_crypto_info *dev = ctx->dev; ++ struct rk_cipher_rctx *rctx = skcipher_request_ctx(req); + +- ctx->mode = RK_CRYPTO_TDES_SELECT; +- return rk_handle_req(dev, req); ++ rctx->mode = RK_CRYPTO_TDES_SELECT; ++ return rk_cipher_handle_req(req); + } + + static int rk_des3_ede_ecb_decrypt(struct skcipher_request *req) + { +- struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); +- struct rk_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); +- struct rk_crypto_info *dev = ctx->dev; ++ struct rk_cipher_rctx *rctx = skcipher_request_ctx(req); + +- ctx->mode = RK_CRYPTO_TDES_SELECT | RK_CRYPTO_DEC; +- return rk_handle_req(dev, req); ++ rctx->mode = RK_CRYPTO_TDES_SELECT | RK_CRYPTO_DEC; ++ return rk_cipher_handle_req(req); + } + + static int rk_des3_ede_cbc_encrypt(struct skcipher_request *req) + { +- struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); +- struct rk_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); +- struct rk_crypto_info *dev = ctx->dev; ++ struct rk_cipher_rctx *rctx = skcipher_request_ctx(req); + +- ctx->mode = RK_CRYPTO_TDES_SELECT | RK_CRYPTO_TDES_CHAINMODE_CBC; +- return rk_handle_req(dev, req); ++ rctx->mode = RK_CRYPTO_TDES_SELECT | RK_CRYPTO_TDES_CHAINMODE_CBC; ++ return rk_cipher_handle_req(req); + } + + static int rk_des3_ede_cbc_decrypt(struct skcipher_request *req) + { +- struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); +- struct rk_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); +- struct rk_crypto_info *dev = ctx->dev; ++ struct rk_cipher_rctx *rctx = skcipher_request_ctx(req); + +- ctx->mode = RK_CRYPTO_TDES_SELECT | RK_CRYPTO_TDES_CHAINMODE_CBC | ++ rctx->mode = RK_CRYPTO_TDES_SELECT | RK_CRYPTO_TDES_CHAINMODE_CBC | + RK_CRYPTO_DEC; +- return rk_handle_req(dev, req); ++ return rk_cipher_handle_req(req); + } + +-static void rk_ablk_hw_init(struct rk_crypto_info *dev) ++static void rk_cipher_hw_init(struct rk_crypto_info *dev, struct skcipher_request *req) + { +- struct skcipher_request *req = +- skcipher_request_cast(dev->async_req); + struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req); + struct crypto_tfm *tfm = crypto_skcipher_tfm(cipher); ++ struct rk_cipher_rctx *rctx = skcipher_request_ctx(req); + struct rk_cipher_ctx *ctx = crypto_skcipher_ctx(cipher); +- u32 ivsize, block, conf_reg = 0; ++ u32 block, conf_reg = 0; + + block = crypto_tfm_alg_blocksize(tfm); +- ivsize = crypto_skcipher_ivsize(cipher); + + if (block == DES_BLOCK_SIZE) { +- ctx->mode |= RK_CRYPTO_TDES_FIFO_MODE | ++ rctx->mode |= RK_CRYPTO_TDES_FIFO_MODE | + RK_CRYPTO_TDES_BYTESWAP_KEY | + RK_CRYPTO_TDES_BYTESWAP_IV; +- CRYPTO_WRITE(dev, RK_CRYPTO_TDES_CTRL, ctx->mode); +- memcpy_toio(dev->reg + RK_CRYPTO_TDES_IV_0, req->iv, ivsize); ++ CRYPTO_WRITE(dev, RK_CRYPTO_TDES_CTRL, rctx->mode); ++ memcpy_toio(dev->reg + RK_CRYPTO_TDES_KEY1_0, ctx->key, ctx->keylen); + conf_reg = RK_CRYPTO_DESSEL; + } else { +- ctx->mode |= RK_CRYPTO_AES_FIFO_MODE | ++ rctx->mode |= RK_CRYPTO_AES_FIFO_MODE | + RK_CRYPTO_AES_KEY_CHANGE | + RK_CRYPTO_AES_BYTESWAP_KEY | + RK_CRYPTO_AES_BYTESWAP_IV; + if (ctx->keylen == AES_KEYSIZE_192) +- ctx->mode |= RK_CRYPTO_AES_192BIT_key; ++ rctx->mode |= RK_CRYPTO_AES_192BIT_key; + else if (ctx->keylen == AES_KEYSIZE_256) +- ctx->mode |= RK_CRYPTO_AES_256BIT_key; +- CRYPTO_WRITE(dev, RK_CRYPTO_AES_CTRL, ctx->mode); +- memcpy_toio(dev->reg + RK_CRYPTO_AES_IV_0, req->iv, ivsize); ++ rctx->mode |= RK_CRYPTO_AES_256BIT_key; ++ CRYPTO_WRITE(dev, RK_CRYPTO_AES_CTRL, rctx->mode); ++ memcpy_toio(dev->reg + RK_CRYPTO_AES_KEY_0, ctx->key, ctx->keylen); + } + conf_reg |= RK_CRYPTO_BYTESWAP_BTFIFO | + RK_CRYPTO_BYTESWAP_BRFIFO; +@@ -231,189 +279,196 @@ static void rk_ablk_hw_init(struct rk_cr + RK_CRYPTO_BCDMA_ERR_ENA | RK_CRYPTO_BCDMA_DONE_ENA); + } + +-static void crypto_dma_start(struct rk_crypto_info *dev) +-{ +- CRYPTO_WRITE(dev, RK_CRYPTO_BRDMAS, dev->addr_in); +- CRYPTO_WRITE(dev, RK_CRYPTO_BRDMAL, dev->count / 4); +- CRYPTO_WRITE(dev, RK_CRYPTO_BTDMAS, dev->addr_out); ++static void crypto_dma_start(struct rk_crypto_info *dev, ++ struct scatterlist *sgs, ++ struct scatterlist *sgd, unsigned int todo) ++{ ++ CRYPTO_WRITE(dev, RK_CRYPTO_BRDMAS, sg_dma_address(sgs)); ++ CRYPTO_WRITE(dev, RK_CRYPTO_BRDMAL, todo); ++ CRYPTO_WRITE(dev, RK_CRYPTO_BTDMAS, sg_dma_address(sgd)); + CRYPTO_WRITE(dev, RK_CRYPTO_CTRL, RK_CRYPTO_BLOCK_START | + _SBF(RK_CRYPTO_BLOCK_START, 16)); + } + +-static int rk_set_data_start(struct rk_crypto_info *dev) ++static int rk_cipher_run(struct crypto_engine *engine, void *async_req) + { +- int err; +- struct skcipher_request *req = +- skcipher_request_cast(dev->async_req); +- struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); +- struct rk_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); +- u32 ivsize = crypto_skcipher_ivsize(tfm); +- u8 *src_last_blk = page_address(sg_page(dev->sg_src)) + +- dev->sg_src->offset + dev->sg_src->length - ivsize; +- +- /* Store the iv that need to be updated in chain mode. +- * And update the IV buffer to contain the next IV for decryption mode. +- */ +- if (ctx->mode & RK_CRYPTO_DEC) { +- memcpy(ctx->iv, src_last_blk, ivsize); +- sg_pcopy_to_buffer(dev->first, dev->src_nents, req->iv, +- ivsize, dev->total - ivsize); +- } +- +- err = dev->load_data(dev, dev->sg_src, dev->sg_dst); +- if (!err) +- crypto_dma_start(dev); +- return err; +-} +- +-static int rk_ablk_start(struct rk_crypto_info *dev) +-{ +- struct skcipher_request *req = +- skcipher_request_cast(dev->async_req); +- unsigned long flags; ++ struct skcipher_request *areq = container_of(async_req, struct skcipher_request, base); ++ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); ++ struct rk_cipher_rctx *rctx = skcipher_request_ctx(areq); ++ struct scatterlist *sgs, *sgd; + int err = 0; ++ int ivsize = crypto_skcipher_ivsize(tfm); ++ int offset; ++ u8 iv[AES_BLOCK_SIZE]; ++ u8 biv[AES_BLOCK_SIZE]; ++ u8 *ivtouse = areq->iv; ++ unsigned int len = areq->cryptlen; ++ unsigned int todo; ++ struct skcipher_alg *alg = crypto_skcipher_alg(tfm); ++ struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.skcipher); ++ struct rk_crypto_info *rkc = rctx->dev; + +- dev->left_bytes = req->cryptlen; +- dev->total = req->cryptlen; +- dev->sg_src = req->src; +- dev->first = req->src; +- dev->src_nents = sg_nents(req->src); +- dev->sg_dst = req->dst; +- dev->dst_nents = sg_nents(req->dst); +- dev->aligned = 1; +- +- spin_lock_irqsave(&dev->lock, flags); +- rk_ablk_hw_init(dev); +- err = rk_set_data_start(dev); +- spin_unlock_irqrestore(&dev->lock, flags); +- return err; +-} ++ err = pm_runtime_resume_and_get(rkc->dev); ++ if (err) ++ return err; + +-static void rk_iv_copyback(struct rk_crypto_info *dev) +-{ +- struct skcipher_request *req = +- skcipher_request_cast(dev->async_req); +- struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); +- struct rk_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); +- u32 ivsize = crypto_skcipher_ivsize(tfm); ++ algt->stat_req++; ++ rkc->nreq++; + +- /* Update the IV buffer to contain the next IV for encryption mode. */ +- if (!(ctx->mode & RK_CRYPTO_DEC)) { +- if (dev->aligned) { +- memcpy(req->iv, sg_virt(dev->sg_dst) + +- dev->sg_dst->length - ivsize, ivsize); +- } else { +- memcpy(req->iv, dev->addr_vir + +- dev->count - ivsize, ivsize); ++ ivsize = crypto_skcipher_ivsize(tfm); ++ if (areq->iv && crypto_skcipher_ivsize(tfm) > 0) { ++ if (rctx->mode & RK_CRYPTO_DEC) { ++ offset = areq->cryptlen - ivsize; ++ scatterwalk_map_and_copy(rctx->backup_iv, areq->src, ++ offset, ivsize, 0); + } + } +-} + +-static void rk_update_iv(struct rk_crypto_info *dev) +-{ +- struct skcipher_request *req = +- skcipher_request_cast(dev->async_req); +- struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); +- struct rk_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); +- u32 ivsize = crypto_skcipher_ivsize(tfm); +- u8 *new_iv = NULL; ++ sgs = areq->src; ++ sgd = areq->dst; + +- if (ctx->mode & RK_CRYPTO_DEC) { +- new_iv = ctx->iv; +- } else { +- new_iv = page_address(sg_page(dev->sg_dst)) + +- dev->sg_dst->offset + dev->sg_dst->length - ivsize; ++ while (sgs && sgd && len) { ++ if (!sgs->length) { ++ sgs = sg_next(sgs); ++ sgd = sg_next(sgd); ++ continue; ++ } ++ if (rctx->mode & RK_CRYPTO_DEC) { ++ /* we backup last block of source to be used as IV at next step */ ++ offset = sgs->length - ivsize; ++ scatterwalk_map_and_copy(biv, sgs, offset, ivsize, 0); ++ } ++ if (sgs == sgd) { ++ err = dma_map_sg(rkc->dev, sgs, 1, DMA_BIDIRECTIONAL); ++ if (err <= 0) { ++ err = -EINVAL; ++ goto theend_iv; ++ } ++ } else { ++ err = dma_map_sg(rkc->dev, sgs, 1, DMA_TO_DEVICE); ++ if (err <= 0) { ++ err = -EINVAL; ++ goto theend_iv; ++ } ++ err = dma_map_sg(rkc->dev, sgd, 1, DMA_FROM_DEVICE); ++ if (err <= 0) { ++ err = -EINVAL; ++ goto theend_sgs; ++ } ++ } ++ err = 0; ++ rk_cipher_hw_init(rkc, areq); ++ if (ivsize) { ++ if (ivsize == DES_BLOCK_SIZE) ++ memcpy_toio(rkc->reg + RK_CRYPTO_TDES_IV_0, ivtouse, ivsize); ++ else ++ memcpy_toio(rkc->reg + RK_CRYPTO_AES_IV_0, ivtouse, ivsize); ++ } ++ reinit_completion(&rkc->complete); ++ rkc->status = 0; ++ ++ todo = min(sg_dma_len(sgs), len); ++ len -= todo; ++ crypto_dma_start(rkc, sgs, sgd, todo / 4); ++ wait_for_completion_interruptible_timeout(&rkc->complete, ++ msecs_to_jiffies(2000)); ++ if (!rkc->status) { ++ dev_err(rkc->dev, "DMA timeout\n"); ++ err = -EFAULT; ++ goto theend; ++ } ++ if (sgs == sgd) { ++ dma_unmap_sg(rkc->dev, sgs, 1, DMA_BIDIRECTIONAL); ++ } else { ++ dma_unmap_sg(rkc->dev, sgs, 1, DMA_TO_DEVICE); ++ dma_unmap_sg(rkc->dev, sgd, 1, DMA_FROM_DEVICE); ++ } ++ if (rctx->mode & RK_CRYPTO_DEC) { ++ memcpy(iv, biv, ivsize); ++ ivtouse = iv; ++ } else { ++ offset = sgd->length - ivsize; ++ scatterwalk_map_and_copy(iv, sgd, offset, ivsize, 0); ++ ivtouse = iv; ++ } ++ sgs = sg_next(sgs); ++ sgd = sg_next(sgd); + } + +- if (ivsize == DES_BLOCK_SIZE) +- memcpy_toio(dev->reg + RK_CRYPTO_TDES_IV_0, new_iv, ivsize); +- else if (ivsize == AES_BLOCK_SIZE) +- memcpy_toio(dev->reg + RK_CRYPTO_AES_IV_0, new_iv, ivsize); +-} ++ if (areq->iv && ivsize > 0) { ++ offset = areq->cryptlen - ivsize; ++ if (rctx->mode & RK_CRYPTO_DEC) { ++ memcpy(areq->iv, rctx->backup_iv, ivsize); ++ memzero_explicit(rctx->backup_iv, ivsize); ++ } else { ++ scatterwalk_map_and_copy(areq->iv, areq->dst, offset, ++ ivsize, 0); ++ } ++ } + +-/* return: +- * true some err was occurred +- * fault no err, continue +- */ +-static int rk_ablk_rx(struct rk_crypto_info *dev) +-{ +- int err = 0; +- struct skcipher_request *req = +- skcipher_request_cast(dev->async_req); ++theend: ++ pm_runtime_put_autosuspend(rkc->dev); + +- dev->unload_data(dev); +- if (!dev->aligned) { +- if (!sg_pcopy_from_buffer(req->dst, dev->dst_nents, +- dev->addr_vir, dev->count, +- dev->total - dev->left_bytes - +- dev->count)) { +- err = -EINVAL; +- goto out_rx; +- } +- } +- if (dev->left_bytes) { +- rk_update_iv(dev); +- if (dev->aligned) { +- if (sg_is_last(dev->sg_src)) { +- dev_err(dev->dev, "[%s:%d] Lack of data\n", +- __func__, __LINE__); +- err = -ENOMEM; +- goto out_rx; +- } +- dev->sg_src = sg_next(dev->sg_src); +- dev->sg_dst = sg_next(dev->sg_dst); +- } +- err = rk_set_data_start(dev); ++ local_bh_disable(); ++ crypto_finalize_skcipher_request(engine, areq, err); ++ local_bh_enable(); ++ return 0; ++ ++theend_sgs: ++ if (sgs == sgd) { ++ dma_unmap_sg(rkc->dev, sgs, 1, DMA_BIDIRECTIONAL); + } else { +- rk_iv_copyback(dev); +- /* here show the calculation is over without any err */ +- dev->complete(dev->async_req, 0); +- tasklet_schedule(&dev->queue_task); ++ dma_unmap_sg(rkc->dev, sgs, 1, DMA_TO_DEVICE); ++ dma_unmap_sg(rkc->dev, sgd, 1, DMA_FROM_DEVICE); + } +-out_rx: ++theend_iv: + return err; + } + +-static int rk_ablk_init_tfm(struct crypto_skcipher *tfm) ++static int rk_cipher_tfm_init(struct crypto_skcipher *tfm) + { + struct rk_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); ++ const char *name = crypto_tfm_alg_name(&tfm->base); + struct skcipher_alg *alg = crypto_skcipher_alg(tfm); +- struct rk_crypto_tmp *algt; ++ struct rk_crypto_tmp *algt = container_of(alg, struct rk_crypto_tmp, alg.skcipher); + +- algt = container_of(alg, struct rk_crypto_tmp, alg.skcipher); ++ ctx->fallback_tfm = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK); ++ if (IS_ERR(ctx->fallback_tfm)) { ++ dev_err(algt->dev->dev, "ERROR: Cannot allocate fallback for %s %ld\n", ++ name, PTR_ERR(ctx->fallback_tfm)); ++ return PTR_ERR(ctx->fallback_tfm); ++ } ++ ++ tfm->reqsize = sizeof(struct rk_cipher_rctx) + ++ crypto_skcipher_reqsize(ctx->fallback_tfm); + +- ctx->dev = algt->dev; +- ctx->dev->align_size = crypto_tfm_alg_alignmask(crypto_skcipher_tfm(tfm)) + 1; +- ctx->dev->start = rk_ablk_start; +- ctx->dev->update = rk_ablk_rx; +- ctx->dev->complete = rk_crypto_complete; +- ctx->dev->addr_vir = (char *)__get_free_page(GFP_KERNEL); ++ ctx->enginectx.op.do_one_request = rk_cipher_run; + +- return ctx->dev->addr_vir ? ctx->dev->enable_clk(ctx->dev) : -ENOMEM; ++ return 0; + } + +-static void rk_ablk_exit_tfm(struct crypto_skcipher *tfm) ++static void rk_cipher_tfm_exit(struct crypto_skcipher *tfm) + { + struct rk_cipher_ctx *ctx = crypto_skcipher_ctx(tfm); + +- free_page((unsigned long)ctx->dev->addr_vir); +- ctx->dev->disable_clk(ctx->dev); ++ memzero_explicit(ctx->key, ctx->keylen); ++ crypto_free_skcipher(ctx->fallback_tfm); + } + + struct rk_crypto_tmp rk_ecb_aes_alg = { +- .type = ALG_TYPE_CIPHER, ++ .type = CRYPTO_ALG_TYPE_SKCIPHER, + .alg.skcipher = { + .base.cra_name = "ecb(aes)", + .base.cra_driver_name = "ecb-aes-rk", + .base.cra_priority = 300, +- .base.cra_flags = CRYPTO_ALG_ASYNC, ++ .base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, + .base.cra_blocksize = AES_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct rk_cipher_ctx), + .base.cra_alignmask = 0x0f, + .base.cra_module = THIS_MODULE, + +- .init = rk_ablk_init_tfm, +- .exit = rk_ablk_exit_tfm, ++ .init = rk_cipher_tfm_init, ++ .exit = rk_cipher_tfm_exit, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = rk_aes_setkey, +@@ -423,19 +478,19 @@ struct rk_crypto_tmp rk_ecb_aes_alg = { + }; + + struct rk_crypto_tmp rk_cbc_aes_alg = { +- .type = ALG_TYPE_CIPHER, ++ .type = CRYPTO_ALG_TYPE_SKCIPHER, + .alg.skcipher = { + .base.cra_name = "cbc(aes)", + .base.cra_driver_name = "cbc-aes-rk", + .base.cra_priority = 300, +- .base.cra_flags = CRYPTO_ALG_ASYNC, ++ .base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, + .base.cra_blocksize = AES_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct rk_cipher_ctx), + .base.cra_alignmask = 0x0f, + .base.cra_module = THIS_MODULE, + +- .init = rk_ablk_init_tfm, +- .exit = rk_ablk_exit_tfm, ++ .init = rk_cipher_tfm_init, ++ .exit = rk_cipher_tfm_exit, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, +@@ -446,19 +501,19 @@ struct rk_crypto_tmp rk_cbc_aes_alg = { + }; + + struct rk_crypto_tmp rk_ecb_des_alg = { +- .type = ALG_TYPE_CIPHER, ++ .type = CRYPTO_ALG_TYPE_SKCIPHER, + .alg.skcipher = { + .base.cra_name = "ecb(des)", + .base.cra_driver_name = "ecb-des-rk", + .base.cra_priority = 300, +- .base.cra_flags = CRYPTO_ALG_ASYNC, ++ .base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, + .base.cra_blocksize = DES_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct rk_cipher_ctx), + .base.cra_alignmask = 0x07, + .base.cra_module = THIS_MODULE, + +- .init = rk_ablk_init_tfm, +- .exit = rk_ablk_exit_tfm, ++ .init = rk_cipher_tfm_init, ++ .exit = rk_cipher_tfm_exit, + .min_keysize = DES_KEY_SIZE, + .max_keysize = DES_KEY_SIZE, + .setkey = rk_des_setkey, +@@ -468,19 +523,19 @@ struct rk_crypto_tmp rk_ecb_des_alg = { + }; + + struct rk_crypto_tmp rk_cbc_des_alg = { +- .type = ALG_TYPE_CIPHER, ++ .type = CRYPTO_ALG_TYPE_SKCIPHER, + .alg.skcipher = { + .base.cra_name = "cbc(des)", + .base.cra_driver_name = "cbc-des-rk", + .base.cra_priority = 300, +- .base.cra_flags = CRYPTO_ALG_ASYNC, ++ .base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, + .base.cra_blocksize = DES_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct rk_cipher_ctx), + .base.cra_alignmask = 0x07, + .base.cra_module = THIS_MODULE, + +- .init = rk_ablk_init_tfm, +- .exit = rk_ablk_exit_tfm, ++ .init = rk_cipher_tfm_init, ++ .exit = rk_cipher_tfm_exit, + .min_keysize = DES_KEY_SIZE, + .max_keysize = DES_KEY_SIZE, + .ivsize = DES_BLOCK_SIZE, +@@ -491,19 +546,19 @@ struct rk_crypto_tmp rk_cbc_des_alg = { + }; + + struct rk_crypto_tmp rk_ecb_des3_ede_alg = { +- .type = ALG_TYPE_CIPHER, ++ .type = CRYPTO_ALG_TYPE_SKCIPHER, + .alg.skcipher = { + .base.cra_name = "ecb(des3_ede)", + .base.cra_driver_name = "ecb-des3-ede-rk", + .base.cra_priority = 300, +- .base.cra_flags = CRYPTO_ALG_ASYNC, ++ .base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, + .base.cra_blocksize = DES_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct rk_cipher_ctx), + .base.cra_alignmask = 0x07, + .base.cra_module = THIS_MODULE, + +- .init = rk_ablk_init_tfm, +- .exit = rk_ablk_exit_tfm, ++ .init = rk_cipher_tfm_init, ++ .exit = rk_cipher_tfm_exit, + .min_keysize = DES3_EDE_KEY_SIZE, + .max_keysize = DES3_EDE_KEY_SIZE, + .setkey = rk_tdes_setkey, +@@ -513,19 +568,19 @@ struct rk_crypto_tmp rk_ecb_des3_ede_alg + }; + + struct rk_crypto_tmp rk_cbc_des3_ede_alg = { +- .type = ALG_TYPE_CIPHER, ++ .type = CRYPTO_ALG_TYPE_SKCIPHER, + .alg.skcipher = { + .base.cra_name = "cbc(des3_ede)", + .base.cra_driver_name = "cbc-des3-ede-rk", + .base.cra_priority = 300, +- .base.cra_flags = CRYPTO_ALG_ASYNC, ++ .base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, + .base.cra_blocksize = DES_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct rk_cipher_ctx), + .base.cra_alignmask = 0x07, + .base.cra_module = THIS_MODULE, + +- .init = rk_ablk_init_tfm, +- .exit = rk_ablk_exit_tfm, ++ .init = rk_cipher_tfm_init, ++ .exit = rk_cipher_tfm_exit, + .min_keysize = DES3_EDE_KEY_SIZE, + .max_keysize = DES3_EDE_KEY_SIZE, + .ivsize = DES_BLOCK_SIZE, +--- a/drivers/crypto/Kconfig ++++ b/drivers/crypto/Kconfig +@@ -784,7 +784,12 @@ config CRYPTO_DEV_IMGTEC_HASH + config CRYPTO_DEV_ROCKCHIP + tristate "Rockchip's Cryptographic Engine driver" + depends on OF && ARCH_ROCKCHIP ++ depends on PM ++ select CRYPTO_ECB ++ select CRYPTO_CBC ++ select CRYPTO_DES + select CRYPTO_AES ++ select CRYPTO_ENGINE + select CRYPTO_LIB_DES + select CRYPTO_MD5 + select CRYPTO_SHA1 +@@ -796,6 +801,16 @@ config CRYPTO_DEV_ROCKCHIP + This driver interfaces with the hardware crypto accelerator. + Supporting cbc/ecb chainmode, and aes/des/des3_ede cipher mode. + ++config CRYPTO_DEV_ROCKCHIP_DEBUG ++ bool "Enable Rockchip crypto stats" ++ depends on CRYPTO_DEV_ROCKCHIP ++ depends on DEBUG_FS ++ help ++ Say y to enable Rockchip crypto debug stats. ++ This will create /sys/kernel/debug/rk3288_crypto/stats for displaying ++ the number of requests per algorithm and other internal stats. ++ ++ + config CRYPTO_DEV_ZYNQMP_AES + tristate "Support for Xilinx ZynqMP AES hw accelerator" + depends on ZYNQMP_FIRMWARE || COMPILE_TEST +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -16972,6 +16972,13 @@ F: Documentation/ABI/*/sysfs-driver-hid- + F: drivers/hid/hid-roccat* + F: include/linux/hid-roccat* + ++ROCKCHIP CRYPTO DRIVERS ++M: Corentin Labbe ++L: linux-crypto@vger.kernel.org ++S: Maintained ++F: Documentation/devicetree/bindings/crypto/rockchip,rk3288-crypto.yaml ++F: drivers/crypto/rockchip/ ++ + ROCKCHIP I2S TDM DRIVER + M: Nicolas Frattaroli + L: linux-rockchip@lists.infradead.org +--- /dev/null ++++ b/Documentation/devicetree/bindings/crypto/rockchip,rk3288-crypto.yaml +@@ -0,0 +1,133 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/crypto/rockchip,rk3288-crypto.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Rockchip Electronics Security Accelerator ++ ++maintainers: ++ - Heiko Stuebner ++ ++properties: ++ compatible: ++ enum: ++ - rockchip,rk3288-crypto ++ - rockchip,rk3328-crypto ++ - rockchip,rk3399-crypto ++ ++ reg: ++ maxItems: 1 ++ ++ interrupts: ++ maxItems: 1 ++ ++ clocks: ++ minItems: 3 ++ maxItems: 4 ++ ++ clock-names: ++ minItems: 3 ++ maxItems: 4 ++ ++ resets: ++ minItems: 1 ++ maxItems: 3 ++ ++ reset-names: ++ minItems: 1 ++ maxItems: 3 ++ ++allOf: ++ - if: ++ properties: ++ compatible: ++ contains: ++ const: rockchip,rk3288-crypto ++ then: ++ properties: ++ clocks: ++ minItems: 4 ++ clock-names: ++ items: ++ - const: aclk ++ - const: hclk ++ - const: sclk ++ - const: apb_pclk ++ minItems: 4 ++ resets: ++ maxItems: 1 ++ reset-names: ++ items: ++ - const: crypto-rst ++ maxItems: 1 ++ - if: ++ properties: ++ compatible: ++ contains: ++ const: rockchip,rk3328-crypto ++ then: ++ properties: ++ clocks: ++ maxItems: 3 ++ clock-names: ++ items: ++ - const: hclk_master ++ - const: hclk_slave ++ - const: sclk ++ maxItems: 3 ++ resets: ++ maxItems: 1 ++ reset-names: ++ items: ++ - const: crypto-rst ++ maxItems: 1 ++ - if: ++ properties: ++ compatible: ++ contains: ++ const: rockchip,rk3399-crypto ++ then: ++ properties: ++ clocks: ++ maxItems: 3 ++ clock-names: ++ items: ++ - const: hclk_master ++ - const: hclk_slave ++ - const: sclk ++ maxItems: 3 ++ resets: ++ minItems: 3 ++ reset-names: ++ items: ++ - const: rst_master ++ - const: rst_slave ++ - const: crypto-rst ++ minItems: 3 ++ ++required: ++ - compatible ++ - reg ++ - interrupts ++ - clocks ++ - clock-names ++ - resets ++ - reset-names ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ #include ++ crypto@ff8a0000 { ++ compatible = "rockchip,rk3288-crypto"; ++ reg = <0xff8a0000 0x4000>; ++ interrupts = ; ++ clocks = <&cru ACLK_CRYPTO>, <&cru HCLK_CRYPTO>, ++ <&cru SCLK_CRYPTO>, <&cru ACLK_DMAC1>; ++ clock-names = "aclk", "hclk", "sclk", "apb_pclk"; ++ resets = <&cru SRST_CRYPTO>; ++ reset-names = "crypto-rst"; ++ }; +--- a/Documentation/devicetree/bindings/crypto/rockchip-crypto.txt ++++ /dev/null +@@ -1,28 +0,0 @@ +-Rockchip Electronics And Security Accelerator +- +-Required properties: +-- compatible: Should be "rockchip,rk3288-crypto" +-- reg: Base physical address of the engine and length of memory mapped +- region +-- interrupts: Interrupt number +-- clocks: Reference to the clocks about crypto +-- clock-names: "aclk" used to clock data +- "hclk" used to clock data +- "sclk" used to clock crypto accelerator +- "apb_pclk" used to clock dma +-- resets: Must contain an entry for each entry in reset-names. +- See ../reset/reset.txt for details. +-- reset-names: Must include the name "crypto-rst". +- +-Examples: +- +- crypto: cypto-controller@ff8a0000 { +- compatible = "rockchip,rk3288-crypto"; +- reg = <0xff8a0000 0x4000>; +- interrupts = ; +- clocks = <&cru ACLK_CRYPTO>, <&cru HCLK_CRYPTO>, +- <&cru SCLK_CRYPTO>, <&cru ACLK_DMAC1>; +- clock-names = "aclk", "hclk", "sclk", "apb_pclk"; +- resets = <&cru SRST_CRYPTO>; +- reset-names = "crypto-rst"; +- }; +--- a/include/dt-bindings/clock/rk3399-cru.h ++++ b/include/dt-bindings/clock/rk3399-cru.h +@@ -547,8 +547,8 @@ + #define SRST_H_PERILP0 171 + #define SRST_H_PERILP0_NOC 172 + #define SRST_ROM 173 +-#define SRST_CRYPTO_S 174 +-#define SRST_CRYPTO_M 175 ++#define SRST_CRYPTO0_S 174 ++#define SRST_CRYPTO0_M 175 + + /* cru_softrst_con11 */ + #define SRST_P_DCF 176 +@@ -556,7 +556,7 @@ + #define SRST_CM0S 178 + #define SRST_CM0S_DBG 179 + #define SRST_CM0S_PO 180 +-#define SRST_CRYPTO 181 ++#define SRST_CRYPTO0 181 + #define SRST_P_PERILP1_SGRF 182 + #define SRST_P_PERILP1_GRF 183 + #define SRST_CRYPTO1_S 184 +--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi +@@ -1040,6 +1040,17 @@ + (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; + }; + ++ crypto: crypto@ff060000 { ++ compatible = "rockchip,rk3328-crypto"; ++ reg = <0x0 0xff060000 0x0 0x4000>; ++ interrupts = ; ++ clocks = <&cru HCLK_CRYPTO_MST>, <&cru HCLK_CRYPTO_SLV>, ++ <&cru SCLK_CRYPTO>; ++ clock-names = "hclk_master", "hclk_slave", "sclk"; ++ resets = <&cru SRST_CRYPTO>; ++ reset-names = "crypto-rst"; ++ }; ++ + pinctrl: pinctrl { + compatible = "rockchip,rk3328-pinctrl"; + rockchip,grf = <&grf>; +--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +@@ -573,6 +573,26 @@ + status = "disabled"; + }; + ++ crypto0: crypto@ff8b0000 { ++ compatible = "rockchip,rk3399-crypto"; ++ reg = <0x0 0xff8b0000 0x0 0x4000>; ++ interrupts = ; ++ clocks = <&cru HCLK_M_CRYPTO0>, <&cru HCLK_S_CRYPTO0>, <&cru SCLK_CRYPTO0>; ++ clock-names = "hclk_master", "hclk_slave", "sclk"; ++ resets = <&cru SRST_CRYPTO0>, <&cru SRST_CRYPTO0_S>, <&cru SRST_CRYPTO0_M>; ++ reset-names = "rst_master", "rst_slave", "crypto-rst"; ++ }; ++ ++ crypto1: crypto@ff8b8000 { ++ compatible = "rockchip,rk3399-crypto"; ++ reg = <0x0 0xff8b8000 0x0 0x4000>; ++ interrupts = ; ++ clocks = <&cru HCLK_M_CRYPTO1>, <&cru HCLK_S_CRYPTO1>, <&cru SCLK_CRYPTO1>; ++ clock-names = "hclk_master", "hclk_slave", "sclk"; ++ resets = <&cru SRST_CRYPTO1>, <&cru SRST_CRYPTO1_S>, <&cru SRST_CRYPTO1_M>; ++ reset-names = "rst_master", "rst_slave", "crypto-rst"; ++ }; ++ + i2c1: i2c@ff110000 { + compatible = "rockchip,rk3399-i2c"; + reg = <0x0 0xff110000 0x0 0x1000>;