From patchwork Tue Jul 13 18:58:57 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Pawe=C5=82_Jarosz?= X-Patchwork-Id: 1504766 X-Patchwork-Delegate: ykai007@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=DqtlNEAu; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GPVLL4Hxyz9sX1 for ; Wed, 14 Jul 2021 04:59:38 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 7E82182C8A; Tue, 13 Jul 2021 20:59:24 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="DqtlNEAu"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 030A582C3C; Tue, 13 Jul 2021 20:59:19 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,SPF_HELO_NONE,UPPERCASE_50_75 autolearn=no autolearn_force=no version=3.4.2 Received: from mail-lf1-x130.google.com (mail-lf1-x130.google.com [IPv6:2a00:1450:4864:20::130]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id D67FD82BFF for ; Tue, 13 Jul 2021 20:59:11 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=paweljarosz3691@gmail.com Received: by mail-lf1-x130.google.com with SMTP id q16so15905783lfa.5 for ; Tue, 13 Jul 2021 11:59:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=mqnHim/w8pmyTxomlvh84IpSoLvXSvY64l8BC9EEWR8=; b=DqtlNEAuBizf1cWKgun0b+RTWNiAPbtXIsJXTC9Vb6gEkvKhQ+p+S6kKEQM2aurT8+ iZq4ZXvOQSdXZlsWZG5n9lr/LGazlLQgINcsCTNnDoNJJIweWv+yzYvXbr9bx0lYo4oI m1i4rJyGlyc260XrwgRW839XPecs78eGUbPcb8R3Ig9p3p4WXKepUFyCPGuum1Axbxe2 D9Ki366SNv29SKZM41xbAgKMRgOqTg1YYKWUe2PFOWZr7Ld/oyu9MT3lWDrBJLRSBto8 zUhv49R3sNA+aANAQjWqqFcyFPcwj4BQduICRH9X99jLuFKMzUOI2ZuZbpdyF5nmaDY3 mlow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=mqnHim/w8pmyTxomlvh84IpSoLvXSvY64l8BC9EEWR8=; b=GOXWqKYB2BXG1oQDFQLXA5MoQI7nTdGB1Sol72VHVltdbTdz1DCxU3oRERp5kjhQHZ 31Qgq4FUuGGB+Ubu9HhOFGTOZ4C5/i06QBhIAaXNuO0DS7ZbhraGed4OhqKo4w8jbUnr JW3xtjoWMKpzCv4p5SV6ZXzkFUFQzWhBaOu2xY3FaWuyr7TkpSlK8QhHXu1Z2kcX4p3R IBiQGOvDFOvLXeaZtJi7WYBuO5AZ/mt+jey9amd0sMzRN15IgpM6dLo+zDUrNSrIk7Vd cV1msYTp90+eEL/NOmAjuXn/4q7vKDfzcanZNV3x47CfPeF+ACtHDw/qsimeHFsAdrP5 r37w== X-Gm-Message-State: AOAM530l1EA0MRRXQXaVSlwsnn9MS/fM3dbuv7BqZVex/jy+TIZgjvq8 d2n91sPdTgzubNT9vo49Oc6/MXNdQ3ncunk5 X-Google-Smtp-Source: ABdhPJxUflsyuJjIhEH116NKU9thro7vr7Iao35jDnzLjR60V2YLSYKb4OPl/E/LltsOZzamQPRrLQ== X-Received: by 2002:a19:6452:: with SMTP id b18mr4770265lfj.545.1626202751273; Tue, 13 Jul 2021 11:59:11 -0700 (PDT) Received: from gl702vs.mrjay.pl (public146460.cdma.centertel.pl. [31.63.124.28]) by smtp.googlemail.com with ESMTPSA id a10sm1246159lfb.93.2021.07.13.11.59.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 13 Jul 2021 11:59:11 -0700 (PDT) From: =?utf-8?q?Pawe=C5=82_Jarosz?= To: kever.yang@rock-chips.com Cc: sjg@chromium.org, philipp.tomsich@vrull.eu, lukma@denx.de, u-boot@lists.denx.de Subject: [PATCH v6 1/4] rockchip: rk3066: add grf header file Date: Tue, 13 Jul 2021 20:58:57 +0200 Message-Id: <20210713185900.59692-2-paweljarosz3691@gmail.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210713185900.59692-1-paweljarosz3691@gmail.com> References: <20210713185900.59692-1-paweljarosz3691@gmail.com> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.2 at phobos.denx.de X-Virus-Status: Clean grf is needed by various drivers for rk3066 soc. Signed-off-by: Paweł Jarosz Acked-by: Philipp Tomsich --- Changes since v1: - updated to shifted masks Changes since v2: - none Changes since v3: - none Changes since v4: - removed gpio iomux related constants Changes since v5: - removed unintentional tab - updated maintainer email - style related changes .../include/asm/arch-rockchip/grf_rk3066.h | 211 ++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 arch/arm/include/asm/arch-rockchip/grf_rk3066.h -- 2.32.0 diff --git a/arch/arm/include/asm/arch-rockchip/grf_rk3066.h b/arch/arm/include/asm/arch-rockchip/grf_rk3066.h new file mode 100644 index 0000000000..71fdcd0372 --- /dev/null +++ b/arch/arm/include/asm/arch-rockchip/grf_rk3066.h @@ -0,0 +1,211 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2021 Paweł Jarosz + */ + +#ifndef _ASM_ARCH_GRF_RK3066_H +#define _ASM_ARCH_GRF_RK3066_H + +struct rk3066_grf_gpio_lh { + u32 l; + u32 h; +}; + +struct rk3066_grf { + struct rk3066_grf_gpio_lh gpio_dir[7]; + struct rk3066_grf_gpio_lh gpio_do[7]; + struct rk3066_grf_gpio_lh gpio_en[7]; + + u32 gpio0a_iomux; + u32 gpio0b_iomux; + u32 gpio0c_iomux; + u32 gpio0d_iomux; + + u32 gpio1a_iomux; + u32 gpio1b_iomux; + u32 gpio1c_iomux; + u32 gpio1d_iomux; + + u32 gpio2a_iomux; + u32 gpio2b_iomux; + u32 gpio2c_iomux; + u32 gpio2d_iomux; + + u32 gpio3a_iomux; + u32 gpio3b_iomux; + u32 gpio3c_iomux; + u32 gpio3d_iomux; + + u32 gpio4a_iomux; + u32 gpio4b_iomux; + u32 gpio4c_iomux; + u32 gpio4d_iomux; + + u32 reserved0[5]; + + u32 gpio6b_iomux; + + u32 reserved1[2]; + + struct rk3066_grf_gpio_lh gpio_pull[7]; + + u32 soc_con0; + u32 soc_con1; + u32 soc_con2; + + u32 soc_status0; + + u32 dmac1_con[3]; + u32 dmac2_con[4]; + + u32 uoc0_con[3]; + u32 uoc1_con[4]; + u32 ddrc_con; + u32 ddrc_stat; + + u32 reserved2[10]; + + u32 os_reg[4]; +}; + +check_member(rk3066_grf, os_reg[3], 0x01d4); + +/* GRF_GPIO1B_IOMUX */ +enum { + GPIO1B1_SHIFT = 2, + GPIO1B1_MASK = 1 << GPIO1B1_SHIFT, + GPIO1B1_GPIO = 0, + GPIO1B1_UART2_SOUT, + + GPIO1B0_SHIFT = 0, + GPIO1B0_MASK = 1 << GPIO1B0_SHIFT, + GPIO1B0_GPIO = 0, + GPIO1B0_UART2_SIN +}; + +/* GRF_SOC_CON0 */ +enum { + SMC_MUX_CON_SHIFT = 13, + SMC_MUX_CON_MASK = 1 << SMC_MUX_CON_SHIFT, + + NOC_REMAP_SHIFT = 12, + NOC_REMAP_MASK = 1 << NOC_REMAP_SHIFT, + + EMMC_FLASH_SEL_SHIFT = 11, + EMMC_FLASH_SEL_MASK = 1 << EMMC_FLASH_SEL_SHIFT, + + TZPC_REVISION_SHIFT = 7, + TZPC_REVISION_MASK = 0xf << TZPC_REVISION_SHIFT, + + L2CACHE_ACC_SHIFT = 5, + L2CACHE_ACC_MASK = 3 << L2CACHE_ACC_SHIFT, + + L2RD_WAIT_SHIFT = 3, + L2RD_WAIT_MASK = 3 << L2RD_WAIT_SHIFT, + + IMEMRD_WAIT_SHIFT = 1, + IMEMRD_WAIT_MASK = 3 << IMEMRD_WAIT_SHIFT, + + SOC_REMAP_SHIFT = 0, + SOC_REMAP_MASK = 1 << SOC_REMAP_SHIFT, +}; + +/* GRF_SOC_CON1 */ +enum { + RKI2C4_SEL_SHIFT = 15, + RKI2C4_SEL_MASK = 1 << RKI2C4_SEL_SHIFT, + + RKI2C3_SEL_SHIFT = 14, + RKI2C3_SEL_MASK = 1 << RKI2C3_SEL_SHIFT, + + RKI2C2_SEL_SHIFT = 13, + RKI2C2_SEL_MASK = 1 << RKI2C2_SEL_SHIFT, + + RKI2C1_SEL_SHIFT = 12, + RKI2C1_SEL_MASK = 1 << RKI2C1_SEL_SHIFT, + + RKI2C0_SEL_SHIFT = 11, + RKI2C0_SEL_MASK = 1 << RKI2C0_SEL_SHIFT, + + VCODEC_SEL_SHIFT = 10, + VCODEC_SEL_MASK = 1 << VCODEC_SEL_SHIFT, + + PERI_EMEM_PAUSE_SHIFT = 9, + PERI_EMEM_PAUSE_MASK = 1 << PERI_EMEM_PAUSE_SHIFT, + + PERI_USB_PAUSE_SHIFT = 8, + PERI_USB_PAUSE_MASK = 1 << PERI_USB_PAUSE_SHIFT, + + SMC_MUX_MODE_0_SHIFT = 6, + SMC_MUX_MODE_0_MASK = 1 << SMC_MUX_MODE_0_SHIFT, + + SMC_SRAM_MW_0_SHIFT = 4, + SMC_SRAM_MW_0_MASK = 3 << SMC_SRAM_MW_0_SHIFT, + + SMC_REMAP_0_SHIFT = 3, + SMC_REMAP_0_MASK = 1 << SMC_REMAP_0_SHIFT, + + SMC_A_GT_M0_SYNC_SHIFT = 2, + SMC_A_GT_M0_SYNC_MASK = 1 << SMC_A_GT_M0_SYNC_SHIFT, + + EMAC_SPEED_SHIFT = 1, + EMAC_SPEEC_MASK = 1 << EMAC_SPEED_SHIFT, + + EMAC_MODE_SHIFT = 0, + EMAC_MODE_MASK = 1 << EMAC_MODE_SHIFT, +}; + +/* GRF_SOC_CON2 */ +enum { + MSCH4_MAINDDR3_SHIFT = 7, + MSCH4_MAINDDR3_MASK = 1 << MSCH4_MAINDDR3_SHIFT, + MSCH4_MAINDDR3_DDR3 = 1, + + EMAC_NEWRCV_EN_SHIFT = 6, + EMAC_NEWRCV_EN_MASK = 1 << EMAC_NEWRCV_EN_SHIFT, + + SW_ADDR15_EN_SHIFT = 5, + SW_ADDR15_EN_MASK = 1 << SW_ADDR15_EN_SHIFT, + + SW_ADDR16_EN_SHIFT = 4, + SW_ADDR16_EN_MASK = 1 << SW_ADDR16_EN_SHIFT, + + SW_ADDR17_EN_SHIFT = 3, + SW_ADDR17_EN_MASK = 1 << SW_ADDR17_EN_SHIFT, + + BANK2_TO_RANK_EN_SHIFT = 2, + BANK2_TO_RANK_EN_MASK = 1 << BANK2_TO_RANK_EN_SHIFT, + + RANK_TO_ROW15_EN_SHIFT = 1, + RANK_TO_ROW15_EN_MASK = 1 << RANK_TO_ROW15_EN_SHIFT, + + UPCTL_C_ACTIVE_IN_SHIFT = 0, + UPCTL_C_ACTIVE_IN_MASK = 1 << UPCTL_C_ACTIVE_IN_SHIFT, + UPCTL_C_ACTIVE_IN_MAY = 0, + UPCTL_C_ACTIVE_IN_WILL, +}; + +/* GRF_DDRC_CON0 */ +enum { + DTO_LB_SHIFT = 11, + DTO_LB_MASK = 3 << DTO_LB_SHIFT, + + DTO_TE_SHIFT = 9, + DTO_TE_MASK = 3 << DTO_TE_SHIFT, + + DTO_PDR_SHIFT = 7, + DTO_PDR_MASK = 3 << DTO_PDR_SHIFT, + + DTO_PDD_SHIFT = 5, + DTO_PDD_MASK = 3 << DTO_PDD_SHIFT, + + DTO_IOM_SHIFT = 3, + DTO_IOM_MASK = 3 << DTO_IOM_SHIFT, + + DTO_OE_SHIFT = 1, + DTO_OE_MASK = 3 << DTO_OE_SHIFT, + + ATO_AE_SHIFT = 0, + ATO_AE_MASK = 1 << ATO_AE_SHIFT, +}; +#endif From patchwork Tue Jul 13 18:58:58 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Pawe=C5=82_Jarosz?= X-Patchwork-Id: 1504767 X-Patchwork-Delegate: ykai007@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=rhg1Bhc3; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GPVLT4BG0z9sX1 for ; Wed, 14 Jul 2021 04:59:45 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 35BD482C09; Tue, 13 Jul 2021 20:59:27 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="rhg1Bhc3"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 5A8B582C8A; Tue, 13 Jul 2021 20:59:22 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,SPF_HELO_NONE autolearn=unavailable autolearn_force=no version=3.4.2 Received: from mail-lf1-x130.google.com (mail-lf1-x130.google.com [IPv6:2a00:1450:4864:20::130]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 505B882C04 for ; Tue, 13 Jul 2021 20:59:13 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=paweljarosz3691@gmail.com Received: by mail-lf1-x130.google.com with SMTP id 8so40444604lfp.9 for ; Tue, 13 Jul 2021 11:59:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=2CYViCRWmoQJacpdPNgoxV0KN7kIRNwsxBo9oWdIAdo=; b=rhg1Bhc3r1nRs0IGSXRs1dWmmAetCgJGpwO109r1T6ob7tTIZ9UOL1ZH3NgeekjwRE gbtL1hjr2v6aLuT/ULSZTpIq9MaJdsXaQXcBeoXPFG1rquHPBYPNdnIhuSLEAb1yLyi4 8TwziXpRT0BqOLYSMYO4T8mfZ1U4NWrkHuUj0oO7FRsrbtBitSxxt49D82cQmbEpy2uw eJtDfmHKQ4NsfoiTYULUXKk7nHySeukmlr/WrMZTP/InXeshkgT8aFQjTx5YNb5FhgHr Tl+gHX+wTCdkhR9gtVgk88XRXR9jpAScFPWaH+tRTyoMNxiIystMqjlb3lfKuiiI3YrS LFDA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=2CYViCRWmoQJacpdPNgoxV0KN7kIRNwsxBo9oWdIAdo=; b=TTn8GQo/VD7j8/fJ3SgHA6Osy+EDBCxuisT+VS94WMY8kn/tmG3zLocUPzWhmlEKA9 tcDBcAg/A38DPnmONLJXbfy9oj01PjU3sQNxes1wt2uXGchruLz1xBlrzwjsgNuDdS0m 3VILdFAdQONyghFLpmpywZX024EFVKmpbSgkYdpvWTu9/Avs5krIhIHske73bhPBXYf5 P2LpL1vJCkWb2QRW4TxNxC9+Im2SU0rx4by/T+vfaCfAY9pwHb2x6kDftzAiyo0oHfK3 nnMZatLO5m8kHNm1ft/GoAHH4jT/WmfgUqarh82ol9cqQjCFeni9qYP/Kk3vLG80qGBc fVWA== X-Gm-Message-State: AOAM530sS1ChTFdKzBz1hmQ0bKZt7DJ8Ih90KG0Czo9jIB0FPPdRhPKL ey0X+mGwcKvsYQw/BMlB2+I= X-Google-Smtp-Source: ABdhPJzVZyoljZZ+ysgaSQNqkziknwnKe+V5+KHgtKPqi5BdQB7fghwD7DriRp4aQZmsqUnu51sLiw== X-Received: by 2002:a05:6512:230d:: with SMTP id o13mr4425579lfu.557.1626202752612; Tue, 13 Jul 2021 11:59:12 -0700 (PDT) Received: from gl702vs.mrjay.pl (public146460.cdma.centertel.pl. [31.63.124.28]) by smtp.googlemail.com with ESMTPSA id a10sm1246159lfb.93.2021.07.13.11.59.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 13 Jul 2021 11:59:12 -0700 (PDT) From: =?utf-8?q?Pawe=C5=82_Jarosz?= To: kever.yang@rock-chips.com Cc: sjg@chromium.org, philipp.tomsich@vrull.eu, lukma@denx.de, u-boot@lists.denx.de Subject: [PATCH v6 2/4] rockchip: rk3066: add clock driver for rk3066 soc Date: Tue, 13 Jul 2021 20:58:58 +0200 Message-Id: <20210713185900.59692-3-paweljarosz3691@gmail.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210713185900.59692-1-paweljarosz3691@gmail.com> References: <20210713185900.59692-1-paweljarosz3691@gmail.com> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.2 at phobos.denx.de X-Virus-Status: Clean Add clock driver for rk3066 platform. Signed-off-by: Paweł Jarosz Acked-by: Philipp Tomsich --- Changes since v1: - updated to shifted masks - moved clk init to tpl Changes since v2: - none Changes since v3: - none Changes since v4: - updated to current codebase - fixed compilation errors Changes since v5: - various style changes - added clk_enable/clk_disable support for nand and mmc clocks - updated maintainer email - renamed uint32_t to u32 - used #if IS_ENABLED macro instead #ifdef .../include/asm/arch-rockchip/cru_rk3066.h | 203 +++++ drivers/clk/rockchip/Makefile | 1 + drivers/clk/rockchip/clk_rk3066.c | 704 ++++++++++++++++++ 3 files changed, 908 insertions(+) create mode 100644 arch/arm/include/asm/arch-rockchip/cru_rk3066.h create mode 100644 drivers/clk/rockchip/clk_rk3066.c -- 2.32.0 diff --git a/arch/arm/include/asm/arch-rockchip/cru_rk3066.h b/arch/arm/include/asm/arch-rockchip/cru_rk3066.h new file mode 100644 index 0000000000..711366d530 --- /dev/null +++ b/arch/arm/include/asm/arch-rockchip/cru_rk3066.h @@ -0,0 +1,203 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2021 Paweł Jarosz + */ + +#ifndef _ASM_ARCH_CRU_RK3066_H +#define _ASM_ARCH_CRU_RK3066_H + +#define OSC_HZ (24 * 1000 * 1000) + +#define APLL_HZ (1416 * 1000000) +#define APLL_SAFE_HZ (600 * 1000000) +#define GPLL_HZ (594 * 1000000) +#define CPLL_HZ (384 * 1000000) + +/* The SRAM is clocked off aclk_cpu, so we want to max it out for boot speed */ +#define CPU_ACLK_HZ 297000000 +#define CPU_HCLK_HZ 148500000 +#define CPU_PCLK_HZ 74250000 +#define CPU_H2P_HZ 74250000 + +#define PERI_ACLK_HZ 148500000 +#define PERI_HCLK_HZ 148500000 +#define PERI_PCLK_HZ 74250000 + +/* Private data for the clock driver - used by rockchip_get_cru() */ +struct rk3066_clk_priv { + struct rk3066_grf *grf; + struct rk3066_cru *cru; + ulong rate; + bool has_bwadj; +}; + +struct rk3066_cru { + struct rk3066_pll { + u32 con0; + u32 con1; + u32 con2; + u32 con3; + } pll[4]; + u32 cru_mode_con; + u32 cru_clksel_con[35]; + u32 cru_clkgate_con[10]; + u32 reserved1[2]; + u32 cru_glb_srst_fst_value; + u32 cru_glb_srst_snd_value; + u32 reserved2[2]; + u32 cru_softrst_con[9]; + u32 cru_misc_con; + u32 reserved3[2]; + u32 cru_glb_cnt_th; +}; + +check_member(rk3066_cru, cru_glb_cnt_th, 0x0140); + +/* CRU_CLKSEL0_CON */ +enum { + /* a9_core_div: core = core_src / (a9_core_div + 1) */ + A9_CORE_DIV_SHIFT = 9, + A9_CORE_DIV_MASK = 0x1f << A9_CORE_DIV_SHIFT, + CORE_PLL_SHIFT = 8, + CORE_PLL_MASK = 1 << CORE_PLL_SHIFT, + CORE_PLL_SELECT_APLL = 0, + CORE_PLL_SELECT_GPLL, + + /* core peri div: core:core_peri = 2:1, 4:1, 8:1 or 16:1 */ + CORE_PERI_DIV_SHIFT = 6, + CORE_PERI_DIV_MASK = 3 << CORE_PERI_DIV_SHIFT, + + /* aclk_cpu pll selection */ + CPU_ACLK_PLL_SHIFT = 5, + CPU_ACLK_PLL_MASK = 1 << CPU_ACLK_PLL_SHIFT, + CPU_ACLK_PLL_SELECT_APLL = 0, + CPU_ACLK_PLL_SELECT_GPLL, + + /* a9_cpu_div: aclk_cpu = cpu_src / (a9_cpu_div + 1) */ + A9_CPU_DIV_SHIFT = 0, + A9_CPU_DIV_MASK = 0x1f << A9_CPU_DIV_SHIFT, +}; + +/* CRU_CLKSEL1_CON */ +enum { + /* ahb2apb_pclk_div: hclk_cpu:pclk_cpu = 1:1, 2:1 or 4:1 */ + AHB2APB_DIV_SHIFT = 14, + AHB2APB_DIV_MASK = 3 << AHB2APB_DIV_SHIFT, + + /* cpu_pclk_div: aclk_cpu:pclk_cpu = 1:1, 2:1, 4:1 or 8:1 */ + CPU_PCLK_DIV_SHIFT = 12, + CPU_PCLK_DIV_MASK = 3 << CPU_PCLK_DIV_SHIFT, + + /* cpu_hclk_div: aclk_cpu:hclk_cpu = 1:1, 2:1 or 4:1 */ + CPU_HCLK_DIV_SHIFT = 8, + CPU_HCLK_DIV_MASK = 3 << CPU_HCLK_DIV_SHIFT, + + /* core_aclk_div: cire:aclk_core = 1:1, 2:1, 3:1, 4:1 or 8:1 */ + CORE_ACLK_DIV_SHIFT = 3, + CORE_ACLK_DIV_MASK = 7 << CORE_ACLK_DIV_SHIFT, +}; + +/* CRU_CLKSEL10_CON */ +enum { + PERI_SEL_PLL_SHIFT = 15, + PERI_SEL_PLL_MASK = 1 << PERI_SEL_PLL_SHIFT, + PERI_SEL_CPLL = 0, + PERI_SEL_GPLL, + + /* peri pclk div: aclk_bus:pclk_bus = 1:1, 2:1, 4:1 or 8:1 */ + PERI_PCLK_DIV_SHIFT = 12, + PERI_PCLK_DIV_MASK = 3 << PERI_PCLK_DIV_SHIFT, + + /* peripheral bus hclk div:aclk_bus: hclk_bus = 1:1, 2:1 or 4:1 */ + PERI_HCLK_DIV_SHIFT = 8, + PERI_HCLK_DIV_MASK = 3 << PERI_HCLK_DIV_SHIFT, + + /* peri aclk div: aclk_peri = periph_src / (peri_aclk_div + 1) */ + PERI_ACLK_DIV_SHIFT = 0, + PERI_ACLK_DIV_MASK = 0x1f << PERI_ACLK_DIV_SHIFT, +}; + +/* CRU_CLKSEL11_CON */ +enum { + MMC0_DIV_SHIFT = 0, + MMC0_DIV_MASK = 0x3f << MMC0_DIV_SHIFT, +}; + +/* CRU_CLKSEL12_CON */ +enum { + UART_PLL_SHIFT = 15, + UART_PLL_MASK = 1 << UART_PLL_SHIFT, + UART_PLL_SELECT_GENERAL = 0, + UART_PLL_SELECT_CODEC, + + EMMC_DIV_SHIFT = 8, + EMMC_DIV_MASK = 0x3f << EMMC_DIV_SHIFT, + + SDIO_DIV_SHIFT = 0, + SDIO_DIV_MASK = 0x3f << SDIO_DIV_SHIFT, +}; + +/* CRU_CLKSEL24_CON */ +enum { + SARADC_DIV_SHIFT = 8, + SARADC_DIV_MASK = 0xff << SARADC_DIV_SHIFT, +}; + +/* CRU_CLKSEL25_CON */ +enum { + SPI1_DIV_SHIFT = 8, + SPI1_DIV_MASK = 0x7f << SPI1_DIV_SHIFT, + + SPI0_DIV_SHIFT = 0, + SPI0_DIV_MASK = 0x7f << SPI0_DIV_SHIFT, +}; + +/* CRU_CLKSEL34_CON */ +enum { + TSADC_DIV_SHIFT = 0, + TSADC_DIV_MASK = 0xffff << TSADC_DIV_SHIFT, +}; + +/* CRU_MODE_CON */ +enum { + GPLL_MODE_SHIFT = 12, + GPLL_MODE_MASK = 3 << GPLL_MODE_SHIFT, + GPLL_MODE_SLOW = 0, + GPLL_MODE_NORMAL, + GPLL_MODE_DEEP, + + CPLL_MODE_SHIFT = 8, + CPLL_MODE_MASK = 3 << CPLL_MODE_SHIFT, + CPLL_MODE_SLOW = 0, + CPLL_MODE_NORMAL, + CPLL_MODE_DEEP, + + DPLL_MODE_SHIFT = 4, + DPLL_MODE_MASK = 3 << DPLL_MODE_SHIFT, + DPLL_MODE_SLOW = 0, + DPLL_MODE_NORMAL, + DPLL_MODE_DEEP, + + APLL_MODE_SHIFT = 0, + APLL_MODE_MASK = 3 << APLL_MODE_SHIFT, + APLL_MODE_SLOW = 0, + APLL_MODE_NORMAL, + APLL_MODE_DEEP, +}; + +/* CRU_APLL_CON0 */ +enum { + CLKR_SHIFT = 8, + CLKR_MASK = 0x3f << CLKR_SHIFT, + + CLKOD_SHIFT = 0, + CLKOD_MASK = 0x3f << CLKOD_SHIFT, +}; + +/* CRU_APLL_CON1 */ +enum { + CLKF_SHIFT = 0, + CLKF_MASK = 0x1fff << CLKF_SHIFT, +}; + +#endif diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index 913f611a0f..a72d8fe58a 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile @@ -6,6 +6,7 @@ obj-y += clk_pll.o obj-$(CONFIG_ROCKCHIP_PX30) += clk_px30.o obj-$(CONFIG_ROCKCHIP_RK3036) += clk_rk3036.o +obj-$(CONFIG_ROCKCHIP_RK3066) += clk_rk3066.o obj-$(CONFIG_ROCKCHIP_RK3128) += clk_rk3128.o obj-$(CONFIG_ROCKCHIP_RK3188) += clk_rk3188.o obj-$(CONFIG_ROCKCHIP_RK322X) += clk_rk322x.o diff --git a/drivers/clk/rockchip/clk_rk3066.c b/drivers/clk/rockchip/clk_rk3066.c new file mode 100644 index 0000000000..6e8eed1fa2 --- /dev/null +++ b/drivers/clk/rockchip/clk_rk3066.c @@ -0,0 +1,704 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * (C) Copyright 2015 Google, Inc + * (C) Copyright 2016 Heiko Stuebner + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct rk3066_clk_plat { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_rockchip_rk3066a_cru dtd; +#endif +}; + +struct pll_div { + u32 nr; + u32 nf; + u32 no; +}; + +enum { + VCO_MAX_HZ = 1416U * 1000000, + VCO_MIN_HZ = 300 * 1000000, + OUTPUT_MAX_HZ = 1416U * 1000000, + OUTPUT_MIN_HZ = 30 * 1000000, + FREF_MAX_HZ = 1416U * 1000000, + FREF_MIN_HZ = 30 * 1000, +}; + +enum { + /* PLL CON0 */ + PLL_OD_MASK = GENMASK(3, 0), + + /* PLL CON1 */ + PLL_NF_MASK = GENMASK(12, 0), + + /* PLL CON2 */ + PLL_BWADJ_MASK = GENMASK(11, 0), + + /* PLL CON3 */ + PLL_RESET_SHIFT = 5, + + /* GRF_SOC_STATUS0 */ + SOCSTS_DPLL_LOCK = BIT(4), + SOCSTS_APLL_LOCK = BIT(5), + SOCSTS_CPLL_LOCK = BIT(6), + SOCSTS_GPLL_LOCK = BIT(7), +}; + +#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) + +#define PLL_DIVISORS(hz, _nr, _no) {\ + .nr = _nr, .nf = (u32)((u64)hz * _nr * _no / OSC_HZ), .no = _no};\ + _Static_assert(((u64)hz * _nr * _no / OSC_HZ) * OSC_HZ /\ + (_nr * _no) == hz, #hz "Hz cannot be hit with PLL "\ + "divisors on line " __stringify(__LINE__)) + +/* Keep divisors as low as possible to reduce jitter and power usage */ +#if IS_ENABLED(CONFIG_TPL_BUILD) +static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2); +static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 2); +#endif + +static int rkclk_set_pll(struct rk3066_cru *cru, enum rk_clk_id clk_id, + const struct pll_div *div) +{ + int pll_id = rk_pll_id(clk_id); + struct rk3066_pll *pll = &cru->pll[pll_id]; + /* All PLLs have same VCO and output frequency range restrictions. */ + uint vco_hz = OSC_HZ / 1000 * div->nf / div->nr * 1000; + uint output_hz = vco_hz / div->no; + + debug("PLL at %x: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n", + (uint)pll, div->nf, div->nr, div->no, vco_hz, output_hz); + assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ && + output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ && + (div->no == 1 || !(div->no % 2))); + + /* enter reset */ + rk_setreg(&pll->con3, BIT(PLL_RESET_SHIFT)); + + rk_clrsetreg(&pll->con0, + CLKR_MASK | PLL_OD_MASK, + ((div->nr - 1) << CLKR_SHIFT) | (div->no - 1)); + rk_clrsetreg(&pll->con1, CLKF_MASK, div->nf - 1); + + rk_clrsetreg(&pll->con2, PLL_BWADJ_MASK, (div->nf >> 1) - 1); + + /* return from reset */ + rk_clrreg(&pll->con3, BIT(PLL_RESET_SHIFT)); + + return 0; +} + +static int rkclk_configure_ddr(struct rk3066_cru *cru, struct rk3066_grf *grf, + unsigned int hz) +{ + static const struct pll_div dpll_cfg[] = { + {.nf = 25, .nr = 2, .no = 1}, + {.nf = 400, .nr = 9, .no = 2}, + {.nf = 500, .nr = 9, .no = 2}, + {.nf = 100, .nr = 3, .no = 1}, + }; + int cfg; + + switch (hz) { + case 300000000: + cfg = 0; + break; + case 533000000: /* actually 533.3P MHz */ + cfg = 1; + break; + case 666000000: /* actually 666.6P MHz */ + cfg = 2; + break; + case 800000000: + cfg = 3; + break; + default: + debug("Unsupported SDRAM frequency"); + return -EINVAL; + } + + /* pll enter slow-mode */ + rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK, + DPLL_MODE_SLOW << DPLL_MODE_SHIFT); + + rkclk_set_pll(cru, CLK_DDR, &dpll_cfg[cfg]); + + /* wait for pll lock */ + while (!(readl(&grf->soc_status0) & SOCSTS_DPLL_LOCK)) + udelay(1); + + /* PLL enter normal-mode */ + rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK, + DPLL_MODE_NORMAL << DPLL_MODE_SHIFT); + + return 0; +} + +static int rkclk_configure_cpu(struct rk3066_cru *cru, struct rk3066_grf *grf, + unsigned int hz) +{ + static const struct pll_div apll_cfg[] = { + {.nf = 50, .nr = 1, .no = 2}, + {.nf = 59, .nr = 1, .no = 1}, + }; + int div_core_peri, div_aclk_core, cfg; + + /* + * We support two possible frequencies, the safe 600MHz + * which will work with default pmic settings and will + * be set to get away from the 24MHz default and + * the maximum of 1.416Ghz, which boards can set if they + * were able to get pmic support for it. + */ + switch (hz) { + case APLL_SAFE_HZ: + cfg = 0; + div_core_peri = 1; + div_aclk_core = 3; + break; + case APLL_HZ: + cfg = 1; + div_core_peri = 2; + div_aclk_core = 3; + break; + default: + debug("Unsupported ARMCLK frequency"); + return -EINVAL; + } + + /* pll enter slow-mode */ + rk_clrsetreg(&cru->cru_mode_con, APLL_MODE_MASK, + APLL_MODE_SLOW << APLL_MODE_SHIFT); + + rkclk_set_pll(cru, CLK_ARM, &apll_cfg[cfg]); + + /* waiting for pll lock */ + while (!(readl(&grf->soc_status0) & SOCSTS_APLL_LOCK)) + udelay(1); + + /* Set divider for peripherals attached to the cpu core. */ + rk_clrsetreg(&cru->cru_clksel_con[0], + CORE_PERI_DIV_MASK, + div_core_peri << CORE_PERI_DIV_SHIFT); + + /* set up dependent divisor for aclk_core */ + rk_clrsetreg(&cru->cru_clksel_con[1], + CORE_ACLK_DIV_MASK, + div_aclk_core << CORE_ACLK_DIV_SHIFT); + + /* PLL enter normal-mode */ + rk_clrsetreg(&cru->cru_mode_con, APLL_MODE_MASK, + APLL_MODE_NORMAL << APLL_MODE_SHIFT); + + return hz; +} + +/* Get pll rate by id */ +static uint32_t rkclk_pll_get_rate(struct rk3066_cru *cru, + enum rk_clk_id clk_id) +{ + u32 nr, no, nf; + u32 con; + int pll_id = rk_pll_id(clk_id); + struct rk3066_pll *pll = &cru->pll[pll_id]; + static u8 clk_shift[CLK_COUNT] = { + 0xff, APLL_MODE_SHIFT, DPLL_MODE_SHIFT, CPLL_MODE_SHIFT, + GPLL_MODE_SHIFT + }; + uint shift; + + con = readl(&cru->cru_mode_con); + shift = clk_shift[clk_id]; + switch ((con >> shift) & APLL_MODE_MASK >> APLL_MODE_SHIFT) { + case APLL_MODE_SLOW: + return OSC_HZ; + case APLL_MODE_NORMAL: + /* normal mode */ + con = readl(&pll->con0); + no = bitfield_extract_by_mask(con, CLKOD_MASK) + 1; + nr = bitfield_extract_by_mask(con, CLKR_MASK) + 1; + con = readl(&pll->con1); + nf = bitfield_extract_by_mask(con, CLKF_MASK) + 1; + + return (OSC_HZ * nf) / (nr * no); + case APLL_MODE_DEEP: + default: + return 32768; + } +} + +static ulong rockchip_mmc_get_clk(struct rk3066_cru *cru, uint gclk_rate, + int periph) +{ + uint div; + u32 con; + + switch (periph) { + case HCLK_EMMC: + case SCLK_EMMC: + con = readl(&cru->cru_clksel_con[12]); + div = bitfield_extract_by_mask(con, EMMC_DIV_MASK); + break; + case HCLK_SDMMC: + case SCLK_SDMMC: + con = readl(&cru->cru_clksel_con[11]); + div = bitfield_extract_by_mask(con, MMC0_DIV_MASK); + break; + case HCLK_SDIO: + case SCLK_SDIO: + con = readl(&cru->cru_clksel_con[12]); + div = bitfield_extract_by_mask(con, SDIO_DIV_MASK); + break; + default: + return -EINVAL; + } + + return DIV_TO_RATE(gclk_rate, div) / 2; +} + +static ulong rockchip_mmc_set_clk(struct rk3066_cru *cru, uint gclk_rate, + int periph, uint freq) +{ + int src_clk_div; + + debug("%s: gclk_rate=%u\n", __func__, gclk_rate); + /* mmc clock defaulg div 2 internal, need provide double in cru */ + src_clk_div = DIV_ROUND_UP(gclk_rate / 2, freq) - 1; + assert(src_clk_div <= 0x3f); + + switch (periph) { + case HCLK_EMMC: + case SCLK_EMMC: + rk_clrsetreg(&cru->cru_clksel_con[12], + EMMC_DIV_MASK, + src_clk_div << EMMC_DIV_SHIFT); + break; + case HCLK_SDMMC: + case SCLK_SDMMC: + rk_clrsetreg(&cru->cru_clksel_con[11], + MMC0_DIV_MASK, + src_clk_div << MMC0_DIV_SHIFT); + break; + case HCLK_SDIO: + case SCLK_SDIO: + rk_clrsetreg(&cru->cru_clksel_con[12], + SDIO_DIV_MASK, + src_clk_div << SDIO_DIV_SHIFT); + break; + default: + return -EINVAL; + } + + return rockchip_mmc_get_clk(cru, gclk_rate, periph); +} + +static ulong rockchip_spi_get_clk(struct rk3066_cru *cru, uint gclk_rate, + int periph) +{ + uint div; + u32 con; + + switch (periph) { + case SCLK_SPI0: + con = readl(&cru->cru_clksel_con[25]); + div = bitfield_extract_by_mask(con, SPI0_DIV_MASK); + break; + case SCLK_SPI1: + con = readl(&cru->cru_clksel_con[25]); + div = bitfield_extract_by_mask(con, SPI1_DIV_MASK); + break; + default: + return -EINVAL; + } + + return DIV_TO_RATE(gclk_rate, div); +} + +static ulong rockchip_spi_set_clk(struct rk3066_cru *cru, uint gclk_rate, + int periph, uint freq) +{ + int src_clk_div = DIV_ROUND_UP(gclk_rate, freq) - 1; + + assert(src_clk_div < 128); + switch (periph) { + case SCLK_SPI0: + assert(src_clk_div <= SPI0_DIV_MASK >> SPI0_DIV_SHIFT); + rk_clrsetreg(&cru->cru_clksel_con[25], + SPI0_DIV_MASK, + src_clk_div << SPI0_DIV_SHIFT); + break; + case SCLK_SPI1: + assert(src_clk_div <= SPI1_DIV_MASK >> SPI1_DIV_SHIFT); + rk_clrsetreg(&cru->cru_clksel_con[25], + SPI1_DIV_MASK, + src_clk_div << SPI1_DIV_SHIFT); + break; + default: + return -EINVAL; + } + + return rockchip_spi_get_clk(cru, gclk_rate, periph); +} + +static ulong rockchip_saradc_get_clk(struct rk3066_cru *cru, int periph) +{ + u32 div, con; + + switch (periph) { + case SCLK_SARADC: + con = readl(&cru->cru_clksel_con[24]); + div = bitfield_extract_by_mask(con, SARADC_DIV_MASK); + break; + case SCLK_TSADC: + con = readl(&cru->cru_clksel_con[34]); + div = bitfield_extract_by_mask(con, TSADC_DIV_MASK); + break; + default: + return -EINVAL; + } + return DIV_TO_RATE(PERI_PCLK_HZ, div); +} + +static ulong rockchip_saradc_set_clk(struct rk3066_cru *cru, uint hz, + int periph) +{ + int src_clk_div; + + src_clk_div = DIV_ROUND_UP(PERI_PCLK_HZ, hz) - 1; + assert(src_clk_div < 128); + + switch (periph) { + case SCLK_SARADC: + rk_clrsetreg(&cru->cru_clksel_con[24], + SARADC_DIV_MASK, + src_clk_div << SARADC_DIV_SHIFT); + break; + case SCLK_TSADC: + rk_clrsetreg(&cru->cru_clksel_con[34], + SARADC_DIV_MASK, + src_clk_div << SARADC_DIV_SHIFT); + break; + default: + return -EINVAL; + } + + return rockchip_saradc_get_clk(cru, periph); +} + +#if IS_ENABLED(CONFIG_TPL_BUILD) +static void rkclk_init(struct rk3066_cru *cru, struct rk3066_grf *grf) +{ + u32 aclk_div, hclk_div, pclk_div, h2p_div; + + /* pll enter slow-mode */ + rk_clrsetreg(&cru->cru_mode_con, + GPLL_MODE_MASK | + CPLL_MODE_MASK, + GPLL_MODE_SLOW << GPLL_MODE_SHIFT | + CPLL_MODE_SLOW << CPLL_MODE_SHIFT); + + /* init pll */ + rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg); + rkclk_set_pll(cru, CLK_CODEC, &cpll_init_cfg); + + /* waiting for pll lock */ + while ((readl(&grf->soc_status0) & + (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK)) != + (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK)) + udelay(1); + + /* + * cpu clock pll source selection and + * reparent aclk_cpu_pre from apll to gpll + * set up dependent divisors for PCLK/HCLK and ACLK clocks. + */ + aclk_div = DIV_ROUND_UP(GPLL_HZ, CPU_ACLK_HZ) - 1; + assert((aclk_div + 1) * CPU_ACLK_HZ == GPLL_HZ && aclk_div <= 0x1f); + + rk_clrsetreg(&cru->cru_clksel_con[0], + CPU_ACLK_PLL_MASK | + A9_CPU_DIV_MASK, + CPU_ACLK_PLL_SELECT_GPLL << CPU_ACLK_PLL_SHIFT | + aclk_div << A9_CPU_DIV_SHIFT); + + hclk_div = ilog2(CPU_ACLK_HZ / CPU_HCLK_HZ); + assert((1 << hclk_div) * CPU_HCLK_HZ == CPU_ACLK_HZ && hclk_div < 0x3); + pclk_div = ilog2(CPU_ACLK_HZ / CPU_PCLK_HZ); + assert((1 << pclk_div) * CPU_PCLK_HZ == CPU_ACLK_HZ && pclk_div < 0x4); + h2p_div = ilog2(CPU_HCLK_HZ / CPU_H2P_HZ); + assert((1 << h2p_div) * CPU_H2P_HZ == CPU_HCLK_HZ && pclk_div < 0x3); + + rk_clrsetreg(&cru->cru_clksel_con[1], + AHB2APB_DIV_MASK | + CPU_PCLK_DIV_MASK | + CPU_HCLK_DIV_MASK, + h2p_div << AHB2APB_DIV_SHIFT | + pclk_div << CPU_PCLK_DIV_SHIFT | + hclk_div << CPU_HCLK_DIV_SHIFT); + + /* + * peri clock pll source selection and + * set up dependent divisors for PCLK/HCLK and ACLK clocks. + */ + aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1; + assert((aclk_div + 1) * PERI_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f); + + hclk_div = ilog2(PERI_ACLK_HZ / PERI_HCLK_HZ); + assert((1 << hclk_div) * PERI_HCLK_HZ == + PERI_ACLK_HZ && (hclk_div < 0x4)); + + pclk_div = ilog2(PERI_ACLK_HZ / PERI_PCLK_HZ); + assert((1 << pclk_div) * PERI_PCLK_HZ == + PERI_ACLK_HZ && (pclk_div < 0x4)); + + rk_clrsetreg(&cru->cru_clksel_con[10], + PERI_PCLK_DIV_MASK | + PERI_HCLK_DIV_MASK | + PERI_ACLK_DIV_MASK, + PERI_SEL_GPLL << PERI_SEL_PLL_SHIFT | + pclk_div << PERI_PCLK_DIV_SHIFT | + hclk_div << PERI_HCLK_DIV_SHIFT | + aclk_div << PERI_ACLK_DIV_SHIFT); + + /* PLL enter normal-mode */ + rk_clrsetreg(&cru->cru_mode_con, + GPLL_MODE_MASK | + CPLL_MODE_MASK, + GPLL_MODE_NORMAL << GPLL_MODE_SHIFT | + CPLL_MODE_NORMAL << CPLL_MODE_SHIFT); + + rockchip_mmc_set_clk(cru, PERI_HCLK_HZ, HCLK_SDMMC, 16000000); +} +#endif + +static ulong rk3066_clk_get_rate(struct clk *clk) +{ + struct rk3066_clk_priv *priv = dev_get_priv(clk->dev); + ulong new_rate, gclk_rate; + + gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL); + switch (clk->id) { + case 1 ... 4: + new_rate = rkclk_pll_get_rate(priv->cru, clk->id); + break; + case HCLK_EMMC: + case HCLK_SDMMC: + case HCLK_SDIO: + case SCLK_EMMC: + case SCLK_SDMMC: + case SCLK_SDIO: + new_rate = rockchip_mmc_get_clk(priv->cru, PERI_HCLK_HZ, + clk->id); + break; + case SCLK_SPI0: + case SCLK_SPI1: + new_rate = rockchip_spi_get_clk(priv->cru, PERI_PCLK_HZ, + clk->id); + break; + case PCLK_I2C0: + case PCLK_I2C1: + case PCLK_I2C2: + case PCLK_I2C3: + case PCLK_I2C4: + return gclk_rate; + case SCLK_SARADC: + case SCLK_TSADC: + new_rate = rockchip_saradc_get_clk(priv->cru, clk->id); + break; + default: + return -ENOENT; + } + + return new_rate; +} + +static ulong rk3066_clk_set_rate(struct clk *clk, ulong rate) +{ + struct rk3066_clk_priv *priv = dev_get_priv(clk->dev); + struct rk3066_cru *cru = priv->cru; + ulong new_rate; + + switch (clk->id) { + case PLL_APLL: + new_rate = rkclk_configure_cpu(priv->cru, priv->grf, rate); + break; + case CLK_DDR: + new_rate = rkclk_configure_ddr(priv->cru, priv->grf, rate); + break; + case HCLK_EMMC: + case HCLK_SDMMC: + case HCLK_SDIO: + case SCLK_EMMC: + case SCLK_SDMMC: + case SCLK_SDIO: + new_rate = rockchip_mmc_set_clk(cru, PERI_HCLK_HZ, + clk->id, rate); + break; + case SCLK_SPI0: + case SCLK_SPI1: + new_rate = rockchip_spi_set_clk(cru, PERI_PCLK_HZ, + clk->id, rate); + break; + case SCLK_SARADC: + case SCLK_TSADC: + new_rate = rockchip_saradc_set_clk(cru, rate, clk->id); + break; + default: + return -ENOENT; + } + + return new_rate; +} + +static int rk3066_clk_enable(struct clk *clk) +{ + struct rk3066_clk_priv *priv = dev_get_priv(clk->dev); + + switch (clk->id) { + case HCLK_NANDC0: + rk_clrreg(&priv->cru->cru_clkgate_con[5], BIT(9)); + break; + case HCLK_SDMMC: + rk_clrreg(&priv->cru->cru_clkgate_con[5], BIT(10)); + break; + case HCLK_SDIO: + rk_clrreg(&priv->cru->cru_clkgate_con[5], BIT(11)); + break; + } + + return 0; +} + +static int rk3066_clk_disable(struct clk *clk) +{ + struct rk3066_clk_priv *priv = dev_get_priv(clk->dev); + + switch (clk->id) { + case HCLK_NANDC0: + rk_setreg(&priv->cru->cru_clkgate_con[5], BIT(9)); + break; + case HCLK_SDMMC: + rk_setreg(&priv->cru->cru_clkgate_con[5], BIT(10)); + break; + case HCLK_SDIO: + rk_setreg(&priv->cru->cru_clkgate_con[5], BIT(11)); + break; + } + + return 0; +} + +static struct clk_ops rk3066_clk_ops = { + .disable = rk3066_clk_disable, + .enable = rk3066_clk_enable, + .get_rate = rk3066_clk_get_rate, + .set_rate = rk3066_clk_set_rate, +}; + +static int rk3066_clk_of_to_plat(struct udevice *dev) +{ +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + struct rk3066_clk_priv *priv = dev_get_priv(dev); + + priv->cru = dev_read_addr_ptr(dev); +#endif + + return 0; +} + +static int rk3066_clk_probe(struct udevice *dev) +{ + struct rk3066_clk_priv *priv = dev_get_priv(dev); + + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + if (IS_ERR(priv->grf)) + return PTR_ERR(priv->grf); + +#if IS_ENABLED(CONFIG_TPL_BUILD) +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct rk3066_clk_plat *plat = dev_get_plat(dev); + + priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]); +#endif + + rkclk_init(priv->cru, priv->grf); + + /* Init CPU frequency */ + rkclk_configure_cpu(priv->cru, priv->grf, APLL_SAFE_HZ); +#endif + + return 0; +} + +static int rk3066_clk_bind(struct udevice *dev) +{ + int ret; + struct udevice *sys_child; + struct sysreset_reg *priv; + + /* The reset driver does not have a device node, so bind it here */ + ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset", + &sys_child); + if (ret) { + debug("Warning: No sysreset driver: ret=%d\n", ret); + } else { + priv = malloc(sizeof(struct sysreset_reg)); + priv->glb_srst_fst_value = offsetof(struct rk3066_cru, + cru_glb_srst_fst_value); + priv->glb_srst_snd_value = offsetof(struct rk3066_cru, + cru_glb_srst_snd_value); + dev_set_priv(sys_child, priv); + } + +#if CONFIG_IS_ENABLED(RESET_ROCKCHIP) + ret = offsetof(struct rk3066_cru, cru_softrst_con[0]); + ret = rockchip_reset_bind(dev, ret, 9); + if (ret) + debug("Warning: software reset driver bind failed\n"); +#endif + + return 0; +} + +static const struct udevice_id rk3066_clk_ids[] = { + { .compatible = "rockchip,rk3066a-cru" }, + { } +}; + +U_BOOT_DRIVER(rockchip_rk3066a_cru) = { + .name = "rockchip_rk3066a_cru", + .id = UCLASS_CLK, + .of_match = rk3066_clk_ids, + .priv_auto = sizeof(struct rk3066_clk_priv), + .plat_auto = sizeof(struct rk3066_clk_plat), + .ops = &rk3066_clk_ops, + .bind = rk3066_clk_bind, + .of_to_plat = rk3066_clk_of_to_plat, + .probe = rk3066_clk_probe, +}; From patchwork Tue Jul 13 18:58:59 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Pawe=C5=82_Jarosz?= X-Patchwork-Id: 1504768 X-Patchwork-Delegate: ykai007@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=F/ILaP28; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GPVLg04j7z9sX1 for ; Wed, 14 Jul 2021 04:59:54 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 2EC1282DE8; Tue, 13 Jul 2021 20:59:35 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="F/ILaP28"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 9BFDD82C35; Tue, 13 Jul 2021 20:59:23 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,SPF_HELO_NONE autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-lf1-x133.google.com (mail-lf1-x133.google.com [IPv6:2a00:1450:4864:20::133]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 5B4DF82C0B for ; Tue, 13 Jul 2021 20:59:14 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=paweljarosz3691@gmail.com Received: by mail-lf1-x133.google.com with SMTP id i5so22321071lfe.2 for ; Tue, 13 Jul 2021 11:59:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=qnqb66FCp2otiD+Mxle9eDNeeD+Ag754dFOE7WYSCM4=; b=F/ILaP28VKcD+sSD8E0OLTth4RR8pJPAyHZIg2ZgHV3AUcIT9mqFfUqaInlrPB7xsP d5/r5/Y15yJVMK6zFEgNEsHVx819uoDKcy0WfSR+1f7MGkXK4npFzhYPkW76bYU3SuNc 8/fS6EpY4aGkAzgWQz2RQxhSgjHmz9YpASOq4j0x9W51ES9bp/PoPAZ0U8UyeM5/kL4H OLt/Gko7y37Nz8ZvfV7iTyeP9HPCGQLSPIRWW4V3Yj0FqvNhFvFzTDeWNOagmK0JK6ae nMsQnHSwBefTr43ll6DJsHza42KTNC94RCVYNbjJeVOROzE/f4hYekMNLlBmOScTQgwJ ZZrw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=qnqb66FCp2otiD+Mxle9eDNeeD+Ag754dFOE7WYSCM4=; b=tH0VyZP+a8mDNbL8QlyCDOu7J1wCqsCtBYwCGEb9yL4SYjcSZzx1T2n/fCT9oWp2ky pCxKkVs1ICWDqql0/Z6VdpuElpQnvq54ohwsh/SIs6xIH7be71yrkIgnThSouwg83Fkt nLvq3U5/yZ9kVkP96pshC2/NXxZqApQ9TLE0crweEl7uYiRDUOzoCbS0rRLSLdrFCld8 MwplQVmyJLK3b8A2mjujEp8B7tVwvdWOBI0H6Qe6bpk5KyU63eMVETEiSguGzTYDj4g7 iCZEm3tcpMF44qCHiTJ6kfOryzqR/LMniY5khqjCidz7ZnkR0hiKNJSvoZziblZqzvR3 1Wvg== X-Gm-Message-State: AOAM531iA1+6dgsgD60xOgUz7FgCtN76Yoj985cUK08fo8/oMNOV0WTH u4mphs4zfcLj3QhoWj8quF8= X-Google-Smtp-Source: ABdhPJyyRV6PssBRfjzx95W8q6TWWp1MntN+NcxkYNh6kj7XbvsZlyyrLFREbrpiDlwXRhz49GHOtQ== X-Received: by 2002:a05:6512:3da3:: with SMTP id k35mr4693825lfv.555.1626202753803; Tue, 13 Jul 2021 11:59:13 -0700 (PDT) Received: from gl702vs.mrjay.pl (public146460.cdma.centertel.pl. [31.63.124.28]) by smtp.googlemail.com with ESMTPSA id a10sm1246159lfb.93.2021.07.13.11.59.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 13 Jul 2021 11:59:13 -0700 (PDT) From: =?utf-8?q?Pawe=C5=82_Jarosz?= To: kever.yang@rock-chips.com Cc: sjg@chromium.org, philipp.tomsich@vrull.eu, lukma@denx.de, u-boot@lists.denx.de Subject: [PATCH v6 3/4] rockchip: rk3066: add rk3066 pinctrl driver Date: Tue, 13 Jul 2021 20:58:59 +0200 Message-Id: <20210713185900.59692-4-paweljarosz3691@gmail.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210713185900.59692-1-paweljarosz3691@gmail.com> References: <20210713185900.59692-1-paweljarosz3691@gmail.com> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.2 at phobos.denx.de X-Virus-Status: Clean Add driver supporting pin multiplexing on rk3066 platform. Signed-off-by: Paweł Jarosz --- Changes since v1: - updated to shifted masks - added nand support Changes since v2: - none Changes since v3: - none Changes since v4: - updated driver to pinctrl full Changes since v5: - none drivers/pinctrl/rockchip/Makefile | 1 + drivers/pinctrl/rockchip/pinctrl-rk3066.c | 113 ++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 drivers/pinctrl/rockchip/pinctrl-rk3066.c -- 2.32.0 diff --git a/drivers/pinctrl/rockchip/Makefile b/drivers/pinctrl/rockchip/Makefile index fcf19f877a..7d03f8101d 100644 --- a/drivers/pinctrl/rockchip/Makefile +++ b/drivers/pinctrl/rockchip/Makefile @@ -5,6 +5,7 @@ obj-y += pinctrl-rockchip-core.o obj-$(CONFIG_ROCKCHIP_PX30) += pinctrl-px30.o obj-$(CONFIG_ROCKCHIP_RK3036) += pinctrl-rk3036.o +obj-$(CONFIG_ROCKCHIP_RK3066) += pinctrl-rk3066.o obj-$(CONFIG_ROCKCHIP_RK3128) += pinctrl-rk3128.o obj-$(CONFIG_ROCKCHIP_RK3188) += pinctrl-rk3188.o obj-$(CONFIG_ROCKCHIP_RK322X) += pinctrl-rk322x.o diff --git a/drivers/pinctrl/rockchip/pinctrl-rk3066.c b/drivers/pinctrl/rockchip/pinctrl-rk3066.c new file mode 100644 index 0000000000..8faba05a4a --- /dev/null +++ b/drivers/pinctrl/rockchip/pinctrl-rk3066.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2021 Rockchip Electronics Co., Ltd + */ + +#include +#include +#include +#include +#include +#include + +#include "pinctrl-rockchip.h" + +static int rk3066_set_mux(struct rockchip_pin_bank *bank, int pin, int mux) +{ + struct rockchip_pinctrl_priv *priv = bank->priv; + int iomux_num = (pin / 8); + struct regmap *regmap; + int reg, ret, mask, mux_type; + u8 bit; + u32 data; + + regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU) + ? priv->regmap_pmu : priv->regmap_base; + + /* get basic quadrupel of mux registers and the correct reg inside */ + mux_type = bank->iomux[iomux_num].type; + reg = bank->iomux[iomux_num].offset; + reg += rockchip_get_mux_data(mux_type, pin, &bit, &mask); + + data = (mask << (bit + 16)); + data |= (mux & mask) << bit; + ret = regmap_write(regmap, reg, data); + + return ret; +} + +#define RK3066_PULL_OFFSET 0x118 +#define RK3066_PULL_PINS_PER_REG 16 +#define RK3066_PULL_BANK_STRIDE 8 + +static void rk3066_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, + int pin_num, struct regmap **regmap, + int *reg, u8 *bit) +{ + struct rockchip_pinctrl_priv *priv = bank->priv; + + *regmap = priv->regmap_base; + *reg = RK3066_PULL_OFFSET; + *reg += bank->bank_num * RK3066_PULL_BANK_STRIDE; + *reg += (pin_num / RK3066_PULL_PINS_PER_REG) * 4; + + *bit = pin_num % RK3066_PULL_PINS_PER_REG; +}; + +static int rk3066_set_pull(struct rockchip_pin_bank *bank, + int pin_num, int pull) +{ + struct regmap *regmap; + int reg, ret; + u8 bit; + u32 data; + + if (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT && + pull != PIN_CONFIG_BIAS_DISABLE) + return -ENOTSUPP; + + rk3066_calc_pull_reg_and_bit(bank, pin_num, ®map, ®, &bit); + data = BIT(bit + 16); + if (pull == PIN_CONFIG_BIAS_DISABLE) + data |= BIT(bit); + ret = regmap_write(regmap, reg, data); + + return ret; +} + +static struct rockchip_pin_bank rk3066_pin_banks[] = { + PIN_BANK(0, 32, "gpio0"), + PIN_BANK(1, 32, "gpio1"), + PIN_BANK(2, 32, "gpio2"), + PIN_BANK(3, 32, "gpio3"), + PIN_BANK(4, 32, "gpio4"), + PIN_BANK(6, 16, "gpio6"), +}; + +static struct rockchip_pin_ctrl rk3066_pin_ctrl = { + .pin_banks = rk3066_pin_banks, + .nr_banks = ARRAY_SIZE(rk3066_pin_banks), + .grf_mux_offset = 0xa8, + .set_mux = rk3066_set_mux, + .set_pull = rk3066_set_pull, +}; + +static const struct udevice_id rk3066_pinctrl_ids[] = { + { + .compatible = "rockchip,rk3066a-pinctrl", + .data = (ulong)&rk3066_pin_ctrl + }, + {} +}; + +U_BOOT_DRIVER(rockchip_rk3066a_pinctrl) = { + .name = "rockchip_rk3066a_pinctrl", + .id = UCLASS_PINCTRL, + .of_match = rk3066_pinctrl_ids, + .priv_auto = sizeof(struct rockchip_pinctrl_priv), + .ops = &rockchip_pinctrl_ops, +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + .bind = dm_scan_fdt_dev, +#endif + .probe = rockchip_pinctrl_probe, +}; From patchwork Tue Jul 13 18:59:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Pawe=C5=82_Jarosz?= X-Patchwork-Id: 1504769 X-Patchwork-Delegate: ykai007@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=YcCKZkep; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GPVLs2hc1z9sX1 for ; Wed, 14 Jul 2021 05:00:05 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 45A4682E0C; Tue, 13 Jul 2021 20:59:40 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="YcCKZkep"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id BBE1F82DBD; Tue, 13 Jul 2021 20:59:29 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,SPF_HELO_NONE autolearn=unavailable autolearn_force=no version=3.4.2 Received: from mail-lf1-x135.google.com (mail-lf1-x135.google.com [IPv6:2a00:1450:4864:20::135]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 2BD5482BEE for ; Tue, 13 Jul 2021 20:59:16 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=paweljarosz3691@gmail.com Received: by mail-lf1-x135.google.com with SMTP id a18so52113312lfs.10 for ; Tue, 13 Jul 2021 11:59:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=drVoESmAHiN0kcIGM2lExbrVPYIvF1CqAs+wUACOPbw=; b=YcCKZkep3VdeGhzwXgY7WsyK9mzXFPOo3B9xexIygS/tyQaeTZlXQBiaDetZtlj3Lv Y4XSh6gppn/Hhpwcnpg/EaGba2xAzjuVceorgYCNGUF86yJAiuvviYV3sAZW5wreeVVM 8/nko6bPLu5RHg98U85uf/+9EBkf7PpztX4THgXoE2dcaqiywKF5pdr3zoc+V9N2Gdyz t6tkySAU092kHCAI6OY2XwK64oAyORDT4DfMs2slWr+kX1eGzw1iKFvq/7c1C4okGhAk xmj6K4+XhFqCtvRnUw2Pk13yKCTu7B31Ur//Q54mrUAxTIlNzybLDhc18Wfh6HBRqCSe 8DqQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=drVoESmAHiN0kcIGM2lExbrVPYIvF1CqAs+wUACOPbw=; b=NChhFLteinIoLoJvPwsLcq/1F6JuE8t+mtHrFCDpwJmugemBcmH9t+OVdYHTeasZo9 iFPgJUEP1ijJZV1eGqEzRVjvzTC6b0pEm3LZ51OTFKxU16K5mMGCrOhTO7WMNUkymwWz oaFFAPvbgqgkvRktJw3ScbhkHGCiOotES+mXWk8wk1Lgtc5cRJ/w6h5epEuOU7BoWosN 6cJRmdUXk43kGmW8Xjr8pEkUJC4icRC/ou+pHYS4LxoQ3KjBwV8yFDh7lKwWNf7hxV2t JEgNbhN85vVOsdX2vRZakglVMNyz1vRvXP3E7Xs0ImQYCOH16PeP+YiG5Jq585B8Cbax iLTA== X-Gm-Message-State: AOAM5305+z9f1wKerIW9NCffFEfJ3Wa7CTBz+HtV8s+OM1YBcIFs6C/B tGzfZI5Nt+TSJ2GTyOEHCdD1krMn07KPpMLh X-Google-Smtp-Source: ABdhPJwmUcjRLOMrXt+6ZAV865JjTXCX3yoMvChHs07er6mKrBpUhKM+iesd5NlXwyChnH59kB4M2Q== X-Received: by 2002:a19:6e0d:: with SMTP id j13mr4572104lfc.108.1626202755180; Tue, 13 Jul 2021 11:59:15 -0700 (PDT) Received: from gl702vs.mrjay.pl (public146460.cdma.centertel.pl. [31.63.124.28]) by smtp.googlemail.com with ESMTPSA id a10sm1246159lfb.93.2021.07.13.11.59.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 13 Jul 2021 11:59:14 -0700 (PDT) From: =?utf-8?q?Pawe=C5=82_Jarosz?= To: kever.yang@rock-chips.com Cc: sjg@chromium.org, philipp.tomsich@vrull.eu, lukma@denx.de, u-boot@lists.denx.de Subject: [PATCH v6 4/4] rockchip: rk3066: add sdram driver Date: Tue, 13 Jul 2021 20:59:00 +0200 Message-Id: <20210713185900.59692-5-paweljarosz3691@gmail.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210713185900.59692-1-paweljarosz3691@gmail.com> References: <20210713185900.59692-1-paweljarosz3691@gmail.com> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.2 at phobos.denx.de X-Virus-Status: Clean Add rockchip rk3066 sdram driver Signed-off-by: Paweł Jarosz Acked-by: Simon Glass Acked-by: Philipp Tomsich --- Changes since v1: - use common rockchip_sdram_size - moved sdram init from sdram_init.c Changes since v2: - none Changes since v3: - none Changes since v4: - updated to current codebase - fixed compilation errors Changes since v5: - fixed various style issues - added arch-rockchip/hardware.h include - used BIT macro - used #if IS_ENABLED macro instead of #ifdef drivers/ram/rockchip/Makefile | 1 + drivers/ram/rockchip/sdram_rk3066.c | 942 ++++++++++++++++++++++++++++ 2 files changed, 943 insertions(+) create mode 100644 drivers/ram/rockchip/sdram_rk3066.c -- 2.32.0 diff --git a/drivers/ram/rockchip/Makefile b/drivers/ram/rockchip/Makefile index ca1c289b88..6d530c29af 100644 --- a/drivers/ram/rockchip/Makefile +++ b/drivers/ram/rockchip/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_ROCKCHIP_PX30) += sdram_px30.o sdram_pctl_px30.o sdram_phy_px30.o obj-$(CONFIG_ROCKCHIP_RK3368) = dmc-rk3368.o +obj-$(CONFIG_ROCKCHIP_RK3066) = sdram_rk3066.o obj-$(CONFIG_ROCKCHIP_RK3128) = sdram_rk3128.o obj-$(CONFIG_ROCKCHIP_RK3188) = sdram_rk3188.o obj-$(CONFIG_ROCKCHIP_RK322X) = sdram_rk322x.o diff --git a/drivers/ram/rockchip/sdram_rk3066.c b/drivers/ram/rockchip/sdram_rk3066.c new file mode 100644 index 0000000000..0dd0a496aa --- /dev/null +++ b/drivers/ram/rockchip/sdram_rk3066.c @@ -0,0 +1,942 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * (C) Copyright 2015 Google, Inc + * Copyright 2014 Rockchip Inc. + * + * Adapted from the very similar rk3188 ddr init. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct chan_info { + struct rk3288_ddr_pctl *pctl; + struct rk3288_ddr_publ *publ; + struct rk3188_msch *msch; +}; + +struct dram_info { + struct chan_info chan[1]; + struct ram_info info; + struct clk ddr_clk; + struct rk3066_cru *cru; + struct rk3066_grf *grf; + struct rk3066_sgrf *sgrf; + struct rk3188_pmu *pmu; +}; + +struct rk3066_sdram_params { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_rockchip_rk3066_dmc of_plat; +#endif + struct rk3288_sdram_channel ch[2]; + struct rk3288_sdram_pctl_timing pctl_timing; + struct rk3288_sdram_phy_timing phy_timing; + struct rk3288_base_params base; + int num_channels; + struct regmap *map; +}; + +const int ddrconf_table[] = { + /* + * [5:4] row(13+n) + * [1:0] col(9+n), assume bw=2 + * row col,bw + */ + 0, + (2 << DDRCONF_ROW_SHIFT) | 1 << DDRCONF_COL_SHIFT, + (1 << DDRCONF_ROW_SHIFT) | 1 << DDRCONF_COL_SHIFT, + (0 << DDRCONF_ROW_SHIFT) | 1 << DDRCONF_COL_SHIFT, + (2 << DDRCONF_ROW_SHIFT) | 2 << DDRCONF_COL_SHIFT, + (1 << DDRCONF_ROW_SHIFT) | 2 << DDRCONF_COL_SHIFT, + (0 << DDRCONF_ROW_SHIFT) | 2 << DDRCONF_COL_SHIFT, + (1 << DDRCONF_ROW_SHIFT) | 0 << DDRCONF_COL_SHIFT, + (0 << DDRCONF_ROW_SHIFT) | 0 << DDRCONF_COL_SHIFT, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +}; + +#define TEST_PATTEN 0x5aa5f00f +#define DQS_GATE_TRAINING_ERROR_RANK0 BIT(4) +#define DQS_GATE_TRAINING_ERROR_RANK1 BIT(5) + +#if IS_ENABLED(CONFIG_TPL_BUILD) +static void copy_to_reg(u32 *dest, const u32 *src, u32 n) +{ + int i; + + for (i = 0; i < n / sizeof(u32); i++) { + writel(*src, dest); + src++; + dest++; + } +} + +static void ddr_reset(struct rk3066_cru *cru, u32 ch, u32 ctl, u32 phy) +{ + u32 phy_ctl_srstn_shift = 13; + u32 ctl_psrstn_shift = 11; + u32 ctl_srstn_shift = 10; + u32 phy_psrstn_shift = 9; + u32 phy_srstn_shift = 8; + + rk_clrsetreg(&cru->cru_softrst_con[5], + 1 << phy_ctl_srstn_shift | 1 << ctl_psrstn_shift | + 1 << ctl_srstn_shift | 1 << phy_psrstn_shift | + 1 << phy_srstn_shift, + phy << phy_ctl_srstn_shift | ctl << ctl_psrstn_shift | + ctl << ctl_srstn_shift | phy << phy_psrstn_shift | + phy << phy_srstn_shift); +} + +static void ddr_phy_ctl_reset(struct rk3066_cru *cru, u32 ch, u32 n) +{ + u32 phy_ctl_srstn_shift = 13; + + rk_clrsetreg(&cru->cru_softrst_con[5], + 1 << phy_ctl_srstn_shift, n << phy_ctl_srstn_shift); +} + +static void phy_pctrl_reset(struct rk3066_cru *cru, + struct rk3288_ddr_publ *publ, + int channel) +{ + int i; + + ddr_reset(cru, channel, 1, 1); + udelay(1); + clrbits_le32(&publ->acdllcr, ACDLLCR_DLLSRST); + for (i = 0; i < 4; i++) + clrbits_le32(&publ->datx8[i].dxdllcr, DXDLLCR_DLLSRST); + + udelay(10); + setbits_le32(&publ->acdllcr, ACDLLCR_DLLSRST); + for (i = 0; i < 4; i++) + setbits_le32(&publ->datx8[i].dxdllcr, DXDLLCR_DLLSRST); + + udelay(10); + ddr_reset(cru, channel, 1, 0); + udelay(10); + ddr_reset(cru, channel, 0, 0); + udelay(10); +} + +static void phy_dll_bypass_set(struct rk3288_ddr_publ *publ, + u32 freq) +{ + int i; + + if (freq <= 250000000) { + if (freq <= 150000000) + clrbits_le32(&publ->dllgcr, SBIAS_BYPASS); + else + setbits_le32(&publ->dllgcr, SBIAS_BYPASS); + setbits_le32(&publ->acdllcr, ACDLLCR_DLLDIS); + for (i = 0; i < 4; i++) + setbits_le32(&publ->datx8[i].dxdllcr, + DXDLLCR_DLLDIS); + + setbits_le32(&publ->pir, PIR_DLLBYP); + } else { + clrbits_le32(&publ->dllgcr, SBIAS_BYPASS); + clrbits_le32(&publ->acdllcr, ACDLLCR_DLLDIS); + for (i = 0; i < 4; i++) { + clrbits_le32(&publ->datx8[i].dxdllcr, + DXDLLCR_DLLDIS); + } + + clrbits_le32(&publ->pir, PIR_DLLBYP); + } +} + +static void dfi_cfg(struct rk3288_ddr_pctl *pctl, u32 dramtype) +{ + writel(DFI_INIT_START, &pctl->dfistcfg0); + writel(DFI_DRAM_CLK_SR_EN | DFI_DRAM_CLK_DPD_EN, + &pctl->dfistcfg1); + writel(DFI_PARITY_INTR_EN | DFI_PARITY_EN, &pctl->dfistcfg2); + writel(7 << TLP_RESP_TIME_SHIFT | LP_SR_EN | LP_PD_EN, + &pctl->dfilpcfg0); + + writel(2 << TCTRL_DELAY_TIME_SHIFT, &pctl->dfitctrldelay); + writel(1 << TPHY_WRDATA_TIME_SHIFT, &pctl->dfitphywrdata); + writel(0xf << TPHY_RDLAT_TIME_SHIFT, &pctl->dfitphyrdlat); + writel(2 << TDRAM_CLK_DIS_TIME_SHIFT, &pctl->dfitdramclkdis); + writel(2 << TDRAM_CLK_EN_TIME_SHIFT, &pctl->dfitdramclken); + writel(1, &pctl->dfitphyupdtype0); + + /* cs0 and cs1 write odt enable */ + writel((RANK0_ODT_WRITE_SEL | RANK1_ODT_WRITE_SEL), + &pctl->dfiodtcfg); + /* odt write length */ + writel(7 << ODT_LEN_BL8_W_SHIFT, &pctl->dfiodtcfg1); + /* phyupd and ctrlupd disabled */ + writel(0, &pctl->dfiupdcfg); +} + +static void ddr_set_ddr3_mode(struct rk3066_grf *grf, uint channel, + bool ddr3_mode) +{ + uint mask, val; + + mask = MSCH4_MAINDDR3_MASK << MSCH4_MAINDDR3_SHIFT; + val = ddr3_mode << MSCH4_MAINDDR3_SHIFT; + rk_clrsetreg(&grf->soc_con2, mask, val); +} + +static void ddr_rank_2_row15en(struct rk3066_grf *grf, bool enable) +{ + uint mask, val; + + mask = RANK_TO_ROW15_EN_MASK << RANK_TO_ROW15_EN_SHIFT; + val = enable << RANK_TO_ROW15_EN_SHIFT; + rk_clrsetreg(&grf->soc_con2, mask, val); +} + +static void pctl_cfg(int channel, struct rk3288_ddr_pctl *pctl, + struct rk3066_sdram_params *sdram_params, + struct rk3066_grf *grf) +{ + copy_to_reg(&pctl->togcnt1u, &sdram_params->pctl_timing.togcnt1u, + sizeof(sdram_params->pctl_timing)); + switch (sdram_params->base.dramtype) { + case DDR3: + if (sdram_params->phy_timing.mr[1] & DDR3_DLL_DISABLE) { + writel(sdram_params->pctl_timing.tcl - 3, + &pctl->dfitrddataen); + } else { + writel(sdram_params->pctl_timing.tcl - 2, + &pctl->dfitrddataen); + } + writel(sdram_params->pctl_timing.tcwl - 1, + &pctl->dfitphywrlat); + writel(0 << MDDR_LPDDR2_CLK_STOP_IDLE_SHIFT | DDR3_EN | + DDR2_DDR3_BL_8 | (6 - 4) << TFAW_SHIFT | PD_EXIT_SLOW | + 1 << PD_TYPE_SHIFT | 0 << PD_IDLE_SHIFT, + &pctl->mcfg); + ddr_set_ddr3_mode(grf, channel, true); + break; + } + + setbits_le32(&pctl->scfg, 1); +} + +static void phy_cfg(const struct chan_info *chan, int channel, + struct rk3066_sdram_params *sdram_params) +{ + struct rk3288_ddr_publ *publ = chan->publ; + struct rk3188_msch *msch = chan->msch; + uint ddr_freq_mhz = sdram_params->base.ddr_freq / 1000000; + u32 dinit2; + int i; + + dinit2 = DIV_ROUND_UP(ddr_freq_mhz * 200000, 1000); + /* DDR PHY Timing */ + copy_to_reg(&publ->dtpr[0], &sdram_params->phy_timing.dtpr0, + sizeof(sdram_params->phy_timing)); + writel(sdram_params->base.noc_timing, &msch->ddrtiming); + writel(0x3f, &msch->readlatency); + writel(DIV_ROUND_UP(ddr_freq_mhz * 5120, 1000) << PRT_DLLLOCK_SHIFT | + DIV_ROUND_UP(ddr_freq_mhz * 50, 1000) << PRT_DLLSRST_SHIFT | + 8 << PRT_ITMSRST_SHIFT, &publ->ptr[0]); + writel(DIV_ROUND_UP(ddr_freq_mhz * 500000, 1000) << PRT_DINIT0_SHIFT | + DIV_ROUND_UP(ddr_freq_mhz * 400, 1000) << PRT_DINIT1_SHIFT, + &publ->ptr[1]); + writel(min(dinit2, 0x1ffffU) << PRT_DINIT2_SHIFT | + DIV_ROUND_UP(ddr_freq_mhz * 1000, 1000) << PRT_DINIT3_SHIFT, + &publ->ptr[2]); + + switch (sdram_params->base.dramtype) { + case DDR3: + clrbits_le32(&publ->pgcr, 0x1f); + clrsetbits_le32(&publ->dcr, DDRMD_MASK << DDRMD_SHIFT, + DDRMD_DDR3 << DDRMD_SHIFT); + break; + } + if (sdram_params->base.odt) { + /*dynamic RTT enable */ + for (i = 0; i < 4; i++) + setbits_le32(&publ->datx8[i].dxgcr, DQSRTT | DQRTT); + } else { + /*dynamic RTT disable */ + for (i = 0; i < 4; i++) + clrbits_le32(&publ->datx8[i].dxgcr, DQSRTT | DQRTT); + } +} + +static void phy_init(struct rk3288_ddr_publ *publ) +{ + setbits_le32(&publ->pir, PIR_INIT | PIR_DLLSRST + | PIR_DLLLOCK | PIR_ZCAL | PIR_ITMSRST | PIR_CLRSR); + udelay(1); + while ((readl(&publ->pgsr) & + (PGSR_IDONE | PGSR_DLDONE | PGSR_ZCDONE)) != + (PGSR_IDONE | PGSR_DLDONE | PGSR_ZCDONE)) + ; +} + +static void send_command(struct rk3288_ddr_pctl *pctl, u32 rank, + u32 cmd, u32 arg) +{ + writel((START_CMD | (rank << 20) | arg | cmd), &pctl->mcmd); + udelay(1); + while (readl(&pctl->mcmd) & START_CMD) + ; +} + +static inline void send_command_op(struct rk3288_ddr_pctl *pctl, + u32 rank, u32 cmd, u32 ma, u32 op) +{ + send_command(pctl, rank, cmd, (ma & LPDDR2_MA_MASK) << LPDDR2_MA_SHIFT | + (op & LPDDR2_OP_MASK) << LPDDR2_OP_SHIFT); +} + +static void memory_init(struct rk3288_ddr_publ *publ, + u32 dramtype) +{ + setbits_le32(&publ->pir, + (PIR_INIT | PIR_DRAMINIT | PIR_LOCKBYP + | PIR_ZCALBYP | PIR_CLRSR | PIR_ICPC + | (dramtype == DDR3 ? PIR_DRAMRST : 0))); + udelay(1); + while ((readl(&publ->pgsr) & (PGSR_IDONE | PGSR_DLDONE)) + != (PGSR_IDONE | PGSR_DLDONE)) + ; +} + +static void move_to_config_state(struct rk3288_ddr_publ *publ, + struct rk3288_ddr_pctl *pctl) +{ + unsigned int state; + + while (1) { + state = readl(&pctl->stat) & PCTL_STAT_MSK; + + switch (state) { + case LOW_POWER: + writel(WAKEUP_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MSK) + != ACCESS) + ; + /* wait DLL lock */ + while ((readl(&publ->pgsr) & PGSR_DLDONE) + != PGSR_DLDONE) + ; + /* + * if at low power state,need wakeup first, + * and then enter the config, so + * fallthrough + */ + case ACCESS: + /* fallthrough */ + case INIT_MEM: + writel(CFG_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MSK) != CONFIG) + ; + break; + case CONFIG: + return; + default: + break; + } + } +} + +static void set_bandwidth_ratio(const struct chan_info *chan, int channel, + u32 n, struct rk3066_grf *grf) +{ + struct rk3288_ddr_pctl *pctl = chan->pctl; + struct rk3288_ddr_publ *publ = chan->publ; + struct rk3188_msch *msch = chan->msch; + + if (n == 1) { + setbits_le32(&pctl->ppcfg, 1); + setbits_le32(&msch->ddrtiming, 1 << 31); + /* Data Byte disable*/ + clrbits_le32(&publ->datx8[2].dxgcr, 1); + clrbits_le32(&publ->datx8[3].dxgcr, 1); + /* disable DLL */ + setbits_le32(&publ->datx8[2].dxdllcr, DXDLLCR_DLLDIS); + setbits_le32(&publ->datx8[3].dxdllcr, DXDLLCR_DLLDIS); + } else { + clrbits_le32(&pctl->ppcfg, 1); + clrbits_le32(&msch->ddrtiming, 1 << 31); + /* Data Byte enable*/ + setbits_le32(&publ->datx8[2].dxgcr, 1); + setbits_le32(&publ->datx8[3].dxgcr, 1); + + /* enable DLL */ + clrbits_le32(&publ->datx8[2].dxdllcr, DXDLLCR_DLLDIS); + clrbits_le32(&publ->datx8[3].dxdllcr, DXDLLCR_DLLDIS); + /* reset DLL */ + clrbits_le32(&publ->datx8[2].dxdllcr, DXDLLCR_DLLSRST); + clrbits_le32(&publ->datx8[3].dxdllcr, DXDLLCR_DLLSRST); + udelay(10); + setbits_le32(&publ->datx8[2].dxdllcr, DXDLLCR_DLLSRST); + setbits_le32(&publ->datx8[3].dxdllcr, DXDLLCR_DLLSRST); + } + setbits_le32(&pctl->dfistcfg0, 1 << 2); +} + +static int data_training(const struct chan_info *chan, int channel, + struct rk3066_sdram_params *sdram_params) +{ + unsigned int j; + int ret = 0; + u32 rank; + int i; + u32 step[2] = { PIR_QSTRN, PIR_RVTRN }; + struct rk3288_ddr_publ *publ = chan->publ; + struct rk3288_ddr_pctl *pctl = chan->pctl; + + /* disable auto refresh */ + writel(0, &pctl->trefi); + + if (sdram_params->base.dramtype != LPDDR3) + setbits_le32(&publ->pgcr, 1 << PGCR_DQSCFG_SHIFT); + rank = sdram_params->ch[channel].rank | 1; + for (j = 0; j < ARRAY_SIZE(step); j++) { + /* + * trigger QSTRN and RVTRN + * clear DTDONE status + */ + setbits_le32(&publ->pir, PIR_CLRSR); + + /* trigger DTT */ + setbits_le32(&publ->pir, + PIR_INIT | step[j] | PIR_LOCKBYP | PIR_ZCALBYP | + PIR_CLRSR); + udelay(1); + /* wait echo byte DTDONE */ + while ((readl(&publ->datx8[0].dxgsr[0]) & rank) + != rank) + ; + while ((readl(&publ->datx8[1].dxgsr[0]) & rank) + != rank) + ; + if (!(readl(&pctl->ppcfg) & 1)) { + while ((readl(&publ->datx8[2].dxgsr[0]) + & rank) != rank) + ; + while ((readl(&publ->datx8[3].dxgsr[0]) + & rank) != rank) + ; + } + if (readl(&publ->pgsr) & + (PGSR_DTERR | PGSR_RVERR | PGSR_RVEIRR)) { + ret = -1; + break; + } + } + /* send some auto refresh to complement the lost while DTT */ + for (i = 0; i < (rank > 1 ? 8 : 4); i++) + send_command(pctl, rank, REF_CMD, 0); + + if (sdram_params->base.dramtype != LPDDR3) + clrbits_le32(&publ->pgcr, 1 << PGCR_DQSCFG_SHIFT); + + /* resume auto refresh */ + writel(sdram_params->pctl_timing.trefi, &pctl->trefi); + + return ret; +} + +static void move_to_access_state(const struct chan_info *chan) +{ + struct rk3288_ddr_publ *publ = chan->publ; + struct rk3288_ddr_pctl *pctl = chan->pctl; + unsigned int state; + + while (1) { + state = readl(&pctl->stat) & PCTL_STAT_MSK; + + switch (state) { + case LOW_POWER: + if (((readl(&pctl->stat) >> LP_TRIG_SHIFT) & + LP_TRIG_MASK) == 1) + return; + + writel(WAKEUP_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MSK) != ACCESS) + ; + /* wait DLL lock */ + while ((readl(&publ->pgsr) & PGSR_DLDONE) + != PGSR_DLDONE) + ; + break; + case INIT_MEM: + writel(CFG_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MSK) != CONFIG) + ; + /* fallthrough */ + case CONFIG: + writel(GO_STATE, &pctl->sctl); + while ((readl(&pctl->stat) & PCTL_STAT_MSK) == CONFIG) + ; + break; + case ACCESS: + return; + default: + break; + } + } +} + +static void dram_cfg_rbc(const struct chan_info *chan, u32 chnum, + struct rk3066_sdram_params *sdram_params) +{ + struct rk3288_ddr_publ *publ = chan->publ; + + if (sdram_params->ch[chnum].bk == 3) + clrsetbits_le32(&publ->dcr, PDQ_MASK << PDQ_SHIFT, + 1 << PDQ_SHIFT); + else + clrbits_le32(&publ->dcr, PDQ_MASK << PDQ_SHIFT); + + writel(sdram_params->base.ddrconfig, &chan->msch->ddrconf); +} + +static void dram_all_config(const struct dram_info *dram, + struct rk3066_sdram_params *sdram_params) +{ + unsigned int chan; + u32 sys_reg = 0; + + sys_reg |= sdram_params->base.dramtype << SYS_REG_DDRTYPE_SHIFT; + sys_reg |= (sdram_params->num_channels - 1) << SYS_REG_NUM_CH_SHIFT; + for (chan = 0; chan < sdram_params->num_channels; chan++) { + const struct rk3288_sdram_channel *info = + &sdram_params->ch[chan]; + + sys_reg |= info->row_3_4 << SYS_REG_ROW_3_4_SHIFT(chan); + sys_reg |= 1 << SYS_REG_CHINFO_SHIFT(chan); + sys_reg |= (info->rank - 1) << SYS_REG_RANK_SHIFT(chan); + sys_reg |= (info->col - 9) << SYS_REG_COL_SHIFT(chan); + sys_reg |= info->bk == 3 ? 0 : 1 << SYS_REG_BK_SHIFT(chan); + sys_reg |= (info->cs0_row - 13) << SYS_REG_CS0_ROW_SHIFT(chan); + sys_reg |= (info->cs1_row - 13) << SYS_REG_CS1_ROW_SHIFT(chan); + sys_reg |= (2 >> info->bw) << SYS_REG_BW_SHIFT(chan); + sys_reg |= (2 >> info->dbw) << SYS_REG_DBW_SHIFT(chan); + + dram_cfg_rbc(&dram->chan[chan], chan, sdram_params); + } + if (sdram_params->ch[0].rank == 2) + ddr_rank_2_row15en(dram->grf, 0); + else + ddr_rank_2_row15en(dram->grf, 1); + + writel(sys_reg, &dram->pmu->sys_reg[2]); +} + +static int sdram_rank_bw_detect(struct dram_info *dram, int channel, + struct rk3066_sdram_params *sdram_params) +{ + int reg; + int need_trainig = 0; + const struct chan_info *chan = &dram->chan[channel]; + struct rk3288_ddr_publ *publ = chan->publ; + + ddr_rank_2_row15en(dram->grf, 0); + + if (data_training(chan, channel, sdram_params) < 0) { + debug("first data training fail!\n"); + reg = readl(&publ->datx8[0].dxgsr[0]); + /* Check the result for rank 0 */ + if (channel == 0 && (reg & DQS_GATE_TRAINING_ERROR_RANK0)) { + debug("data training fail!\n"); + return -EIO; + } + + /* Check the result for rank 1 */ + if (reg & DQS_GATE_TRAINING_ERROR_RANK1) { + sdram_params->ch[channel].rank = 1; + clrsetbits_le32(&publ->pgcr, 0xF << 18, + sdram_params->ch[channel].rank << 18); + need_trainig = 1; + } + reg = readl(&publ->datx8[2].dxgsr[0]); + if (reg & (1 << 4)) { + sdram_params->ch[channel].bw = 1; + set_bandwidth_ratio(chan, channel, + sdram_params->ch[channel].bw, + dram->grf); + need_trainig = 1; + } + } + /* Assume the Die bit width are the same with the chip bit width */ + sdram_params->ch[channel].dbw = sdram_params->ch[channel].bw; + + if (need_trainig && + (data_training(chan, channel, sdram_params) < 0)) { + if (sdram_params->base.dramtype == LPDDR3) { + ddr_phy_ctl_reset(dram->cru, channel, 1); + udelay(10); + ddr_phy_ctl_reset(dram->cru, channel, 0); + udelay(10); + } + debug("2nd data training failed!"); + return -EIO; + } + + return 0; +} + +/* + * Detect ram columns and rows. + * @dram: dram info struct + * @channel: channel number to handle + * @sdram_params: sdram parameters, function will fill in col and row values + * + * Returns 0 or negative on error. + */ +static int sdram_col_row_detect(struct dram_info *dram, int channel, + struct rk3066_sdram_params *sdram_params) +{ + int row, col; + unsigned int addr; + const struct chan_info *chan = &dram->chan[channel]; + struct rk3288_ddr_pctl *pctl = chan->pctl; + struct rk3288_ddr_publ *publ = chan->publ; + int ret = 0; + + /* Detect col */ + for (col = 11; col >= 9; col--) { + writel(0, CONFIG_SYS_SDRAM_BASE); + addr = CONFIG_SYS_SDRAM_BASE + + (1 << (col + sdram_params->ch[channel].bw - 1)); + writel(TEST_PATTEN, addr); + if ((readl(addr) == TEST_PATTEN) && + (readl(CONFIG_SYS_SDRAM_BASE) == 0)) + break; + } + if (col == 8) { + debug("Col detect error\n"); + ret = -EINVAL; + goto out; + } else { + sdram_params->ch[channel].col = col; + } + + ddr_rank_2_row15en(dram->grf, 1); + move_to_config_state(publ, pctl); + writel(1, &chan->msch->ddrconf); + move_to_access_state(chan); + /* Detect row, max 15,min13 in rk3066*/ + for (row = 16; row >= 13; row--) { + writel(0, CONFIG_SYS_SDRAM_BASE); + addr = CONFIG_SYS_SDRAM_BASE + (1 << (row + 15 - 1)); + writel(TEST_PATTEN, addr); + if ((readl(addr) == TEST_PATTEN) && + (readl(CONFIG_SYS_SDRAM_BASE) == 0)) + break; + } + if (row == 12) { + debug("Row detect error\n"); + ret = -EINVAL; + } else { + sdram_params->ch[channel].cs1_row = row; + sdram_params->ch[channel].row_3_4 = 0; + debug("chn %d col %d, row %d\n", channel, col, row); + sdram_params->ch[channel].cs0_row = row; + } + +out: + return ret; +} + +static int sdram_get_niu_config(struct rk3066_sdram_params *sdram_params) +{ + int i, tmp, size, ret = 0; + + tmp = sdram_params->ch[0].col - 9; + tmp -= (sdram_params->ch[0].bw == 2) ? 0 : 1; + tmp |= ((sdram_params->ch[0].cs0_row - 13) << 4); + size = ARRAY_SIZE(ddrconf_table) / sizeof(ddrconf_table[0]); + for (i = 0; i < size; i++) + if (tmp == ddrconf_table[i]) + break; + if (i >= size) { + debug("niu config not found\n"); + ret = -EINVAL; + } else { + debug("niu config %d\n", i); + sdram_params->base.ddrconfig = i; + } + + return ret; +} + +static int sdram_init(struct dram_info *dram, + struct rk3066_sdram_params *sdram_params) +{ + int channel; + int zqcr; + int ret; + + if ((sdram_params->base.dramtype == DDR3 && + sdram_params->base.ddr_freq > 800000000)) { + debug("SDRAM frequency is too high!"); + return -E2BIG; + } + + ret = clk_set_rate(&dram->ddr_clk, sdram_params->base.ddr_freq); + if (ret) { + debug("Could not set DDR clock\n"); + return ret; + } + + for (channel = 0; channel < 1; channel++) { + const struct chan_info *chan = &dram->chan[channel]; + struct rk3288_ddr_pctl *pctl = chan->pctl; + struct rk3288_ddr_publ *publ = chan->publ; + + phy_pctrl_reset(dram->cru, publ, channel); + phy_dll_bypass_set(publ, sdram_params->base.ddr_freq); + + dfi_cfg(pctl, sdram_params->base.dramtype); + + pctl_cfg(channel, pctl, sdram_params, dram->grf); + + phy_cfg(chan, channel, sdram_params); + + phy_init(publ); + + writel(POWER_UP_START, &pctl->powctl); + while (!(readl(&pctl->powstat) & POWER_UP_DONE)) + ; + + memory_init(publ, sdram_params->base.dramtype); + move_to_config_state(publ, pctl); + + /* Using 32bit bus width for detect */ + sdram_params->ch[channel].bw = 2; + set_bandwidth_ratio(chan, channel, + sdram_params->ch[channel].bw, dram->grf); + /* + * set cs, using n=3 for detect + * CS0, n=1 + * CS1, n=2 + * CS0 & CS1, n = 3 + */ + sdram_params->ch[channel].rank = 2; + clrsetbits_le32(&publ->pgcr, 0xF << 18, + (sdram_params->ch[channel].rank | 1) << 18); + + /* DS=40ohm,ODT=155ohm */ + zqcr = 1 << ZDEN_SHIFT | 2 << PU_ONDIE_SHIFT | + 2 << PD_ONDIE_SHIFT | 0x19 << PU_OUTPUT_SHIFT | + 0x19 << PD_OUTPUT_SHIFT; + writel(zqcr, &publ->zq1cr[0]); + writel(zqcr, &publ->zq0cr[0]); + + /* Detect the rank and bit-width with data-training */ + writel(1, &chan->msch->ddrconf); + sdram_rank_bw_detect(dram, channel, sdram_params); + + if (sdram_params->base.dramtype == LPDDR3) { + u32 i; + writel(0, &pctl->mrrcfg0); + + for (i = 0; i < 17; i++) + send_command_op(pctl, 1, MRR_CMD, i, 0); + } + writel(4, &chan->msch->ddrconf); + move_to_access_state(chan); + /* DDR3 and LPDDR3 are always 8 bank, no need detect */ + sdram_params->ch[channel].bk = 3; + /* Detect Col and Row number*/ + ret = sdram_col_row_detect(dram, channel, sdram_params); + if (ret) + goto error; + } + /* Find NIU DDR configuration */ + ret = sdram_get_niu_config(sdram_params); + if (ret) + goto error; + + dram_all_config(dram, sdram_params); + debug("%s done\n", __func__); + + return 0; +error: + debug("DRAM init failed!\n"); + hang(); +} + +static int setup_sdram(struct udevice *dev) +{ + struct dram_info *priv = dev_get_priv(dev); + struct rk3066_sdram_params *params = dev_get_plat(dev); + + return sdram_init(priv, params); +} + +static int rk3066_dmc_ofdata_to_platdata(struct udevice *dev) +{ +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + struct rk3066_sdram_params *params = dev_get_plat(dev); + int ret; + + /* rk3066 supports only one-channel */ + params->num_channels = 1; + ret = dev_read_u32_array(dev, "rockchip,pctl-timing", + (u32 *)¶ms->pctl_timing, + sizeof(params->pctl_timing) / sizeof(u32)); + if (ret) { + debug("%s: Cannot read rockchip,pctl-timing\n", __func__); + return -EINVAL; + } + ret = dev_read_u32_array(dev, "rockchip,phy-timing", + (u32 *)¶ms->phy_timing, + sizeof(params->phy_timing) / sizeof(u32)); + if (ret) { + debug("%s: Cannot read rockchip,phy-timing\n", __func__); + return -EINVAL; + } + ret = dev_read_u32_array(dev, "rockchip,sdram-params", + (u32 *)¶ms->base, + sizeof(params->base) / sizeof(u32)); + if (ret) { + debug("%s: Cannot read rockchip,sdram-params\n", __func__); + return -EINVAL; + } + ret = regmap_init_mem(dev_ofnode(dev), ¶ms->map); + if (ret) + return ret; +#endif + + return 0; +} +#endif /* CONFIG_TPL_BUILD */ + +#if CONFIG_IS_ENABLED(OF_PLATDATA) +static int conv_of_plat(struct udevice *dev) +{ + struct rk3066_sdram_params *plat = dev_get_plat(dev); + struct dtd_rockchip_rk3066_dmc *of_plat = &plat->of_plat; + int ret; + + memcpy(&plat->pctl_timing, of_plat->rockchip_pctl_timing, + sizeof(plat->pctl_timing)); + memcpy(&plat->phy_timing, of_plat->rockchip_phy_timing, + sizeof(plat->phy_timing)); + memcpy(&plat->base, of_plat->rockchip_sdram_params, sizeof(plat->base)); + /* rk3066 supports dual-channel, set default channel num to 2 */ + plat->num_channels = 1; + ret = regmap_init_mem_plat(dev, of_plat->reg, + ARRAY_SIZE(of_plat->reg) / 2, &plat->map); + if (ret) + return ret; + + return 0; +} +#endif + +static int rk3066_dmc_probe(struct udevice *dev) +{ +#if IS_ENABLED(CONFIG_TPL_BUILD) + struct rk3066_sdram_params *plat = dev_get_plat(dev); + struct regmap *map; + struct udevice *dev_clk; + int ret; +#endif + struct dram_info *priv = dev_get_priv(dev); + + priv->pmu = syscon_get_first_range(ROCKCHIP_SYSCON_PMU); + +#if IS_ENABLED(CONFIG_TPL_BUILD) +#if CONFIG_IS_ENABLED(OF_PLATDATA) + ret = conv_of_plat(dev); + if (ret) + return ret; +#endif + map = syscon_get_regmap_by_driver_data(ROCKCHIP_SYSCON_NOC); + if (IS_ERR(map)) + return PTR_ERR(map); + priv->chan[0].msch = regmap_get_range(map, 0); + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + + priv->chan[0].pctl = regmap_get_range(plat->map, 0); + priv->chan[0].publ = regmap_get_range(plat->map, 1); + + ret = rockchip_get_clk(&dev_clk); + if (ret) + return ret; + + priv->ddr_clk.id = CLK_DDR; + ret = clk_request(dev_clk, &priv->ddr_clk); + if (ret) + return ret; + + priv->cru = rockchip_get_cru(); + if (IS_ERR(priv->cru)) + return PTR_ERR(priv->cru); + ret = setup_sdram(dev); + if (ret) + return ret; +#else + priv->info.base = CONFIG_SYS_SDRAM_BASE; + priv->info.size = + rockchip_sdram_size((phys_addr_t)&priv->pmu->sys_reg[2]); +#endif + + return 0; +} + +static int rk3066_dmc_get_info(struct udevice *dev, struct ram_info *info) +{ + struct dram_info *priv = dev_get_priv(dev); + + *info = priv->info; + + return 0; +} + +static struct ram_ops rk3066_dmc_ops = { + .get_info = rk3066_dmc_get_info, +}; + +static const struct udevice_id rk3066_dmc_ids[] = { + { .compatible = "rockchip,rk3066-dmc" }, + { } +}; + +U_BOOT_DRIVER(rockchip_rk3066_dmc) = { + .name = "rockchip_rk3066_dmc", + .id = UCLASS_RAM, + .of_match = rk3066_dmc_ids, + .ops = &rk3066_dmc_ops, +#if CONFIG_IS_ENABLED(OF_PLATDATA) + .of_to_plat = rk3066_dmc_ofdata_to_platdata, +#endif + .probe = rk3066_dmc_probe, + .priv_auto = sizeof(struct dram_info), +#if IS_ENABLED(CONFIG_TPL_BUILD) + .plat_auto = sizeof(struct rk3066_sdram_params), +#endif +};