From patchwork Wed May 30 15:06:43 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 922854 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-tegra-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="gDCZrtOp"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 40wvFs3lF2z9s1b for ; Thu, 31 May 2018 01:12:00 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753889AbeE3PL5 (ORCPT ); Wed, 30 May 2018 11:11:57 -0400 Received: from mail-lf0-f68.google.com ([209.85.215.68]:38720 "EHLO mail-lf0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752370AbeE3PKY (ORCPT ); Wed, 30 May 2018 11:10:24 -0400 Received: by mail-lf0-f68.google.com with SMTP id z142-v6so4849643lff.5; Wed, 30 May 2018 08:10:23 -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; bh=Hu3xoZzDE4jadHfA9GevvF77MLBzA74lyZNPbkECnZE=; b=gDCZrtOp9ivWsC0UlaXNzZk9+ZAjfp6H2LUtT6cEfxL/vBP/2q+/5s7lXjjqezPJCo QjRQpyAhFQObL6dZJMHYmeQI+JyC+tj3xF8unLBUALhNT3n+auUmR13L7aTi0cH9NHvP BNGvlykNwa81E7UafBqXtHe/8Uw73FDLkkI6rH1JArHHHy7VpBEWsYSlbC+9o37Rs5xM dl1zb3qT3v0plRf0DktRCvRxzGeDRZou9HsXGMh5G4I50MOAmCFo9H3PGCpKDMntlLq4 o9NYd+X5YzojN+VX3jFwPITvyeypG+n29D99NvVVW1gpXy0i9WVWDJDGH5MSxlAcf/wK PXnQ== 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; bh=Hu3xoZzDE4jadHfA9GevvF77MLBzA74lyZNPbkECnZE=; b=f5Yb3NTLBaR77f5fQS8wmgk4pi1oHvd83/LuJEV6qHe+mjmufdmkX8A3LrTjfPrQUe FpJwjmnwBWv59TSykXmzKNXUj+FYs+vhHZZHwwnERd5yi4QjF5OLGmeuGNK6QCSSYibo pd2W09JZ/spNTSZ2CmR3BoHrHsf7Ynhue4CO00OMCpLCIpCUqd0na7TzgrDtQFKZ2Tnt q616GkZHmvhrwNBtsSed0uiV/i9OkJymgK2Xj9n+ZWrWp4lzAD8DghNAnp33pPXuB1Fo q7ykMlActoc/tTIYrWxMO5/7B2YEgxeXTssZxjqVvgTD4Hjzb9Cdnq4z1gZYGxMNE30M SAeg== X-Gm-Message-State: ALKqPwd1to13HR47QkhCROA6HJ0linihYir3JVCGe4Cmi4txzffFUzgp xfKXR18DkP6SYJD6faznoMU= X-Google-Smtp-Source: ADUXVKI2F96K5mLg4fmiqeqnJ97mJePpmqPyIDTTV8YtRaWZw84TdZvlMxki3r/Twr4e1XuEJVI2fQ== X-Received: by 2002:a19:15da:: with SMTP id 87-v6mr2049548lfv.136.1527693022808; Wed, 30 May 2018 08:10:22 -0700 (PDT) Received: from localhost.localdomain (109-252-91-41.nat.spd-mgts.ru. [109.252.91.41]) by smtp.gmail.com with ESMTPSA id v3-v6sm6982134ljv.61.2018.05.30.08.10.21 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 30 May 2018 08:10:22 -0700 (PDT) From: Dmitry Osipenko To: Thierry Reding , Peter De Schrijver , Jonathan Hunter , Prashant Gaikwad , Michael Turquette , Stephen Boyd , Rob Herring , Mark Rutland Cc: linux-tegra@vger.kernel.org, linux-clk@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v1 1/4] dt: bindings: tegra20-emc: Document interrupt property Date: Wed, 30 May 2018 18:06:43 +0300 Message-Id: <20180530150646.19030-2-digetx@gmail.com> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180530150646.19030-1-digetx@gmail.com> References: <20180530150646.19030-1-digetx@gmail.com> Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org EMC has a dedicated interrupt that is used to notify about completion of HW operations. Document the interrupt property. Signed-off-by: Dmitry Osipenko --- .../devicetree/bindings/arm/tegra/nvidia,tegra20-emc.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-emc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-emc.txt index 4c33b29dc660..a6fe401d0d48 100644 --- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-emc.txt +++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-emc.txt @@ -10,6 +10,7 @@ Properties: and chosen using the ramcode board selector. If omitted, only one set of tables can be present and said tables will be used irrespective of ram-code configuration. +- interrupts : Should contain EMC General interrupt. Child device nodes describe the memory settings for different configurations and clock rates. @@ -20,6 +21,7 @@ Example: #size-cells = < 0 >; compatible = "nvidia,tegra20-emc"; reg = <0x7000f4000 0x200>; + interrupts = <0 78 0x04>; } From patchwork Wed May 30 15:06:44 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 922856 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-tegra-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="J5EW0BGU"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 40wvGw3nHpz9s08 for ; Thu, 31 May 2018 01:12:56 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753839AbeE3PLw (ORCPT ); Wed, 30 May 2018 11:11:52 -0400 Received: from mail-lf0-f66.google.com ([209.85.215.66]:41991 "EHLO mail-lf0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753553AbeE3PK0 (ORCPT ); Wed, 30 May 2018 11:10:26 -0400 Received: by mail-lf0-f66.google.com with SMTP id v135-v6so4857698lfa.9; Wed, 30 May 2018 08:10:24 -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; bh=01PYMgEsBvVg7wtDu9tzcBp0PUsVPyFncK6O6mZm+O0=; b=J5EW0BGU5BfNHA8RQRTBvUvHnhSEqHruOBckHta+qzkUlgetShlmo90lpuLVXB7GZk LezgOwyHMMXeCZxleSY6gVZkQOigJ8HwwsvAUjU6wS/8fG7PQcvtX5bN338h5TnsEqUM EerLzQw6MJXDlZ+QkLxfYDT4UeV+p4qVi7ZzWW5EBj4NfmHMTCggeys2XzYLzQiY3YcK axZf4aepKj1W0zqRk4ejmuIWyqLsspybR2wHScg4zgvtFO3onoKa6LvzlamIkw2nZn90 ib3bZqLUY5JlVRffhBvDMKUaLfl5GwTjffNREigmVX+1AaYZnSbVJ6VTvYcAtzBX8jeF 8O2A== 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; bh=01PYMgEsBvVg7wtDu9tzcBp0PUsVPyFncK6O6mZm+O0=; b=af/u6TXEr50JC4Qb6CizmbnaS/bidVCQxyB4mQh8+xw0q5TqnNLa5uu8YpawsDP5cz JT0xdH78RN9qDOX5LQAyk7Gl7JgVZul065oFTsVFCYXi72GcOa/E1As2FdgOOOpy9jnO NjKy9NkZy3DfGTOyFDkJEjGHpRjAZyLZu9Q1v65kQqLLaMPJqVJCi+SeiPpmneSo6lms vjyeJeoBwlwwTzIBGLK8j2WoE9Ed3f6Oa8uBcJmuWlnv/8cAIkPPz273eYSikLCONHhq FV+qTvajW0RGd2Awg65y/0dYtxA8fWRkNv6LQActziG4zqkde/688OcQ0vRtnixipW5L 5yaw== X-Gm-Message-State: ALKqPweJUVoHDMENs6ya/DW5+vW0tEqUVABfJO7WehY6KIYeJuWA1s8V MAn3dl+ZiAfZbmcUr3JHego= X-Google-Smtp-Source: ADUXVKLc9Q60G40NkYHOlBBEg581d4ahlmJkZSiQUUQjw9UEMbN3Sr6Xu6Ew/EXKgqbD1q8AcTD5xQ== X-Received: by 2002:a19:cf46:: with SMTP id f67-v6mr1935908lfg.101.1527693023913; Wed, 30 May 2018 08:10:23 -0700 (PDT) Received: from localhost.localdomain (109-252-91-41.nat.spd-mgts.ru. [109.252.91.41]) by smtp.gmail.com with ESMTPSA id v3-v6sm6982134ljv.61.2018.05.30.08.10.22 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 30 May 2018 08:10:23 -0700 (PDT) From: Dmitry Osipenko To: Thierry Reding , Peter De Schrijver , Jonathan Hunter , Prashant Gaikwad , Michael Turquette , Stephen Boyd , Rob Herring , Mark Rutland Cc: linux-tegra@vger.kernel.org, linux-clk@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v1 2/4] ARM: dts: tegra20: Add interrupt to External Memory Controller Date: Wed, 30 May 2018 18:06:44 +0300 Message-Id: <20180530150646.19030-3-digetx@gmail.com> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180530150646.19030-1-digetx@gmail.com> References: <20180530150646.19030-1-digetx@gmail.com> Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org Add interrupt entry into the EMC DT node. Signed-off-by: Dmitry Osipenko --- arch/arm/boot/dts/tegra20.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 983dd5c14794..3cd3cb28cfd9 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -609,6 +609,7 @@ memory-controller@7000f400 { compatible = "nvidia,tegra20-emc"; reg = <0x7000f400 0x200>; + interrupts = ; #address-cells = <1>; #size-cells = <0>; }; From patchwork Wed May 30 15:06:45 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 922852 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-tegra-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="VKDGbtTB"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 40wvDC5NDpz9s1d for ; Thu, 31 May 2018 01:10:35 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753739AbeE3PKc (ORCPT ); Wed, 30 May 2018 11:10:32 -0400 Received: from mail-lf0-f65.google.com ([209.85.215.65]:36130 "EHLO mail-lf0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753648AbeE3PK1 (ORCPT ); Wed, 30 May 2018 11:10:27 -0400 Received: by mail-lf0-f65.google.com with SMTP id u4-v6so4857074lff.3; Wed, 30 May 2018 08:10:26 -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; bh=mJbAPOImtc7hZ45o1iBpn/OOLUD0U9g8/4ojUQ0kqv4=; b=VKDGbtTBoIFr/zupCqWoHhWlYscIZsJOdyASHNAaRFE+X5jRoDtp2fqxIgZCMu3XLn 5dOMczKvpmkZ08Z0/5k14l0Wg/Ov5Edg8rMx9eFceoY/ceGfiM67P9cY/3DrlR9qWe2j UDxqEt1ZcQh6YY6zSIRMjMWYVo7vChv0O3oi0gQHqfQQDuOtsuUSxUTqekM0FsOZkM3S qRJkHe04sr4fpRHL99r26+kVw0yckP+EEAaAiStZMMMG406rPNpdNGasT1VyjnoW22Qb kASlYIcPUlv6rDAn6gCg31Cc9AsZKzqSztf/OTdTDnSfWWzeeLf6kxO4VFZz83dxIC/T UmEQ== 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; bh=mJbAPOImtc7hZ45o1iBpn/OOLUD0U9g8/4ojUQ0kqv4=; b=dNe3WHu49oB4fbQgqX32NHaT+1kySBmLmvQH0LF3FGTOyRIQDdPq+nWUHvZHhRu3wC 6EaG2VFz6GxE2ndhN4DqfHUFJFmu99MxXSlzw4XbmRjMCttADbEhHfIC5n43xWp5HOd/ e8KnWL8cjvdesH7gFpyh5+GPZXMHmFWJ1HeCJF6csFtjm7hdsVKcDSo6IVPHsLTNRto2 7Mx2D0GshJ8KeDqZdXBhMVlnhkXHfR2MX7TbdV5X82q0E4uoa6nuWzM3RaOiXu7OyWeC B8K0tmHyDLxBsZ4IC8dh2huDJ+eWYdSzsBgp8H9Qx6zDR/TbeBmvm+dNASebHFuoBx4B KOzQ== X-Gm-Message-State: ALKqPweJKAmAaU/yPs0EtVwsXwcn9NoBuhb9Q2WWv8iSIikxAS9EaIjs sZ35cVaiKeGfEGPcqXy51vTta6v8 X-Google-Smtp-Source: ADUXVKIQk4UQxcDOeMoRPGpVHxjFshTtj3wMw0XKrPZFBfFn9wvyyqmwMhTjha2ybZMlDKgIjkDuIg== X-Received: by 2002:a19:4e86:: with SMTP id u6-v6mr2038331lfk.105.1527693025072; Wed, 30 May 2018 08:10:25 -0700 (PDT) Received: from localhost.localdomain (109-252-91-41.nat.spd-mgts.ru. [109.252.91.41]) by smtp.gmail.com with ESMTPSA id v3-v6sm6982134ljv.61.2018.05.30.08.10.23 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 30 May 2018 08:10:24 -0700 (PDT) From: Dmitry Osipenko To: Thierry Reding , Peter De Schrijver , Jonathan Hunter , Prashant Gaikwad , Michael Turquette , Stephen Boyd , Rob Herring , Mark Rutland Cc: linux-tegra@vger.kernel.org, linux-clk@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v1 3/4] clk: tegra20: Turn EMC clock gate into divider Date: Wed, 30 May 2018 18:06:45 +0300 Message-Id: <20180530150646.19030-4-digetx@gmail.com> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180530150646.19030-1-digetx@gmail.com> References: <20180530150646.19030-1-digetx@gmail.com> Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org Kernel should never gate the EMC clock as it causes immediate lockup, so removing clk-gate functionality doesn't affect anything. Turning EMC clk gate into divider allows to implement glitch-less EMC scaling, avoiding reparenting to a backup clock. Signed-off-by: Dmitry Osipenko --- drivers/clk/tegra/clk-tegra20.c | 39 ++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index cc857d4d4a86..189dbc86ab71 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -578,7 +578,6 @@ static struct tegra_clk tegra20_clks[tegra_clk_max] __initdata = { [tegra_clk_afi] = { .dt_id = TEGRA20_CLK_AFI, .present = true }, [tegra_clk_fuse] = { .dt_id = TEGRA20_CLK_FUSE, .present = true }, [tegra_clk_kfuse] = { .dt_id = TEGRA20_CLK_KFUSE, .present = true }, - [tegra_clk_emc] = { .dt_id = TEGRA20_CLK_EMC, .present = true }, }; static unsigned long tegra20_clk_measure_input_freq(void) @@ -799,19 +798,18 @@ static struct tegra_periph_init_data tegra_periph_nodiv_clk_list[] = { TEGRA_INIT_DATA_NODIV("disp2", mux_pllpdc_clkm, CLK_SOURCE_DISP2, 30, 2, 26, 0, TEGRA20_CLK_DISP2), }; -static void __init tegra20_periph_clk_init(void) +static void __init tegra20_emc_clk_init(void) { - struct tegra_periph_init_data *data; + u32 emc_reg = readl_relaxed(clk_base + CLK_SOURCE_EMC); + u32 use_pllm_ud = BIT(29); struct clk *clk; - unsigned int i; - /* ac97 */ - clk = tegra_clk_register_periph_gate("ac97", "pll_a_out0", - TEGRA_PERIPH_ON_APB, - clk_base, 0, 3, periph_clk_enb_refcnt); - clks[TEGRA20_CLK_AC97] = clk; + if (emc_reg & use_pllm_ud) { + pr_err("%s: un-divided PllM_out0 used as clock source\n", + __func__); + return; + } - /* emc */ clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, ARRAY_SIZE(mux_pllmcp_clkm), CLK_SET_RATE_NO_REPARENT, @@ -822,6 +820,27 @@ static void __init tegra20_periph_clk_init(void) &emc_lock); clks[TEGRA20_CLK_MC] = clk; + clk = clk_register_divider(NULL, "emc", "emc_mux", CLK_IS_CRITICAL, + clk_base + CLK_SOURCE_EMC, 0, 7, + 0, &emc_lock); + clks[TEGRA20_CLK_EMC] = clk; +} + +static void __init tegra20_periph_clk_init(void) +{ + struct tegra_periph_init_data *data; + struct clk *clk; + unsigned int i; + + /* ac97 */ + clk = tegra_clk_register_periph_gate("ac97", "pll_a_out0", + TEGRA_PERIPH_ON_APB, + clk_base, 0, 3, periph_clk_enb_refcnt); + clks[TEGRA20_CLK_AC97] = clk; + + /* emc */ + tegra20_emc_clk_init(); + /* dsi */ clk = tegra_clk_register_periph_gate("dsi", "pll_d", 0, clk_base, 0, 48, periph_clk_enb_refcnt); From patchwork Wed May 30 15:06:46 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 922853 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-tegra-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="gBFbyRlH"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 40wvDF0rljz9s08 for ; Thu, 31 May 2018 01:10:37 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753750AbeE3PKd (ORCPT ); Wed, 30 May 2018 11:10:33 -0400 Received: from mail-lf0-f67.google.com ([209.85.215.67]:33571 "EHLO mail-lf0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753726AbeE3PK2 (ORCPT ); Wed, 30 May 2018 11:10:28 -0400 Received: by mail-lf0-f67.google.com with SMTP id y20-v6so4850236lfy.0; Wed, 30 May 2018 08:10:27 -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; bh=Ib+HUUZ/6Gy54y5TXB8VWU2XCrgOTebAgwV7yVYGt48=; b=gBFbyRlHEJuLVgirbqTSO6olAdy2+bdQdjVm3B38NTZqK/uxJWIM9SHXJ6PHgXbPP9 OagrNTg2lAzqiShChsRhe0uBoiL2F6lQNNb9EA7mlVEzhZfORLYy73+7SLneOFozKob/ WKLbpjybI8v9o1I1MvZb1ncnaEM0KoAi1KYxg2GD5zyexNLBsnuZV96+2c56rzQGckWK l/6KDCqQjlVbG65Qmbhhkjkg/b8LyXd7zWlKSkKYopT34mos0nfLJnqxivjrOQsjr+aE F4vTyFO875cWN6aJ44lV7yZwJKyvadv7H6Way3QWplShBtFTQp6+E/mniIY354pInC20 h1BA== 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; bh=Ib+HUUZ/6Gy54y5TXB8VWU2XCrgOTebAgwV7yVYGt48=; b=hEEP7rg+N3voFmAos6CcyhIFkS7QBrtdxcNbvfU7PKSXdpO20x60ckvDa7HVZdSx+V QJ/B2MPbPUdIOf9cicp4ku8z1NZZ0oZ3sfOh+XiG8Y/nhrYmxGST9WapY2C/kXTY3pno wQOXdiYfBxOtsYOHl4nAvFyCgsyg/tlTDCZlJ7K1e72ncd6W+u0jBRdhqrIrSlkKHU4R 6A1xqLc8jaDqM2iUqkJgHiHRybRJwNHnsHa+4UFNc/jeOUXRkN5WIc66phUw6PGD5qhG WjrANGvIYjT2Xw9zRMG7wKFDtXbQn2BFs3PhUhZ8E6j7783G6bu3oyLGyIXRoA55vHQy iMgA== X-Gm-Message-State: ALKqPwdSma77eOZUZfC3JmZe0Vo+HZgPU8DjwniXqwqOdaCOoGpCFggH dEe1DbFwSXH79qT9TpRM5Jk= X-Google-Smtp-Source: ADUXVKLQiWKBDrFIfFkQc6qj5n6921J0OrryDN9aJmvq2xnnaPOkHx3ptindlXRuasAsZdEPhYXVew== X-Received: by 2002:a19:9855:: with SMTP id a82-v6mr1923195lfe.87.1527693026161; Wed, 30 May 2018 08:10:26 -0700 (PDT) Received: from localhost.localdomain (109-252-91-41.nat.spd-mgts.ru. [109.252.91.41]) by smtp.gmail.com with ESMTPSA id v3-v6sm6982134ljv.61.2018.05.30.08.10.25 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 30 May 2018 08:10:25 -0700 (PDT) From: Dmitry Osipenko To: Thierry Reding , Peter De Schrijver , Jonathan Hunter , Prashant Gaikwad , Michael Turquette , Stephen Boyd , Rob Herring , Mark Rutland Cc: linux-tegra@vger.kernel.org, linux-clk@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v1 4/4] memory: tegra: Introduce Tegra20 EMC driver Date: Wed, 30 May 2018 18:06:46 +0300 Message-Id: <20180530150646.19030-5-digetx@gmail.com> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180530150646.19030-1-digetx@gmail.com> References: <20180530150646.19030-1-digetx@gmail.com> Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org Introduce driver for the External Memory Controller (EMC) found on Tegra20 chips, which controls the external DRAM on the board. The purpose of this driver is to program memory timings for external memory on the EMC clock rate change. Signed-off-by: Dmitry Osipenko --- drivers/memory/tegra/Kconfig | 10 + drivers/memory/tegra/Makefile | 1 + drivers/memory/tegra/tegra20-emc.c | 573 +++++++++++++++++++++++++++++ 3 files changed, 584 insertions(+) create mode 100644 drivers/memory/tegra/tegra20-emc.c diff --git a/drivers/memory/tegra/Kconfig b/drivers/memory/tegra/Kconfig index 6d74e499e18d..34e0b70f5c5f 100644 --- a/drivers/memory/tegra/Kconfig +++ b/drivers/memory/tegra/Kconfig @@ -6,6 +6,16 @@ config TEGRA_MC This driver supports the Memory Controller (MC) hardware found on NVIDIA Tegra SoCs. +config TEGRA20_EMC + bool "NVIDIA Tegra20 External Memory Controller driver" + default y + depends on ARCH_TEGRA_2x_SOC + help + This driver is for the External Memory Controller (EMC) found on + Tegra20 chips. The EMC controls the external DRAM on the board. + This driver is required to change memory timings / clock rate for + external memory. + config TEGRA124_EMC bool "NVIDIA Tegra124 External Memory Controller driver" default y diff --git a/drivers/memory/tegra/Makefile b/drivers/memory/tegra/Makefile index 94ab16ba075b..3971a6b7c487 100644 --- a/drivers/memory/tegra/Makefile +++ b/drivers/memory/tegra/Makefile @@ -10,5 +10,6 @@ tegra-mc-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210.o obj-$(CONFIG_TEGRA_MC) += tegra-mc.o +obj-$(CONFIG_TEGRA20_EMC) += tegra20-emc.o obj-$(CONFIG_TEGRA124_EMC) += tegra124-emc.o obj-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186.o diff --git a/drivers/memory/tegra/tegra20-emc.c b/drivers/memory/tegra/tegra20-emc.c new file mode 100644 index 000000000000..fbd1f85edf23 --- /dev/null +++ b/drivers/memory/tegra/tegra20-emc.c @@ -0,0 +1,573 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Tegra20 External Memory Controller driver + * + * Author: Dmitry Osipenko + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define EMC_INTSTATUS 0x000 +#define EMC_INTMASK 0x004 +#define EMC_TIMING_CONTROL 0x028 +#define EMC_RC 0x02c +#define EMC_RFC 0x030 +#define EMC_RAS 0x034 +#define EMC_RP 0x038 +#define EMC_R2W 0x03c +#define EMC_W2R 0x040 +#define EMC_R2P 0x044 +#define EMC_W2P 0x048 +#define EMC_RD_RCD 0x04c +#define EMC_WR_RCD 0x050 +#define EMC_RRD 0x054 +#define EMC_REXT 0x058 +#define EMC_WDV 0x05c +#define EMC_QUSE 0x060 +#define EMC_QRST 0x064 +#define EMC_QSAFE 0x068 +#define EMC_RDV 0x06c +#define EMC_REFRESH 0x070 +#define EMC_BURST_REFRESH_NUM 0x074 +#define EMC_PDEX2WR 0x078 +#define EMC_PDEX2RD 0x07c +#define EMC_PCHG2PDEN 0x080 +#define EMC_ACT2PDEN 0x084 +#define EMC_AR2PDEN 0x088 +#define EMC_RW2PDEN 0x08c +#define EMC_TXSR 0x090 +#define EMC_TCKE 0x094 +#define EMC_TFAW 0x098 +#define EMC_TRPAB 0x09c +#define EMC_TCLKSTABLE 0x0a0 +#define EMC_TCLKSTOP 0x0a4 +#define EMC_TREFBW 0x0a8 +#define EMC_QUSE_EXTRA 0x0ac +#define EMC_ODT_WRITE 0x0b0 +#define EMC_ODT_READ 0x0b4 +#define EMC_FBIO_CFG5 0x104 +#define EMC_FBIO_CFG6 0x114 +#define EMC_AUTO_CAL_INTERVAL 0x2a8 +#define EMC_CFG_2 0x2b8 +#define EMC_CFG_DIG_DLL 0x2bc +#define EMC_DLL_XFORM_DQS 0x2c0 +#define EMC_DLL_XFORM_QUSE 0x2c4 +#define EMC_ZCAL_REF_CNT 0x2e0 +#define EMC_ZCAL_WAIT_CNT 0x2e4 +#define EMC_CFG_CLKTRIM_0 0x2d0 +#define EMC_CFG_CLKTRIM_1 0x2d4 +#define EMC_CFG_CLKTRIM_2 0x2d8 + +#define EMC_CLKCHANGE_REQ_ENABLE BIT(0) + +#define EMC_TIMING_UPDATE BIT(0) + +#define EMC_CLKCHANGE_COMPLETE_INT BIT(4) + +static const unsigned long emc_timing_registers[] = { + EMC_RC, + EMC_RFC, + EMC_RAS, + EMC_RP, + EMC_R2W, + EMC_W2R, + EMC_R2P, + EMC_W2P, + EMC_RD_RCD, + EMC_WR_RCD, + EMC_RRD, + EMC_REXT, + EMC_WDV, + EMC_QUSE, + EMC_QRST, + EMC_QSAFE, + EMC_RDV, + EMC_REFRESH, + EMC_BURST_REFRESH_NUM, + EMC_PDEX2WR, + EMC_PDEX2RD, + EMC_PCHG2PDEN, + EMC_ACT2PDEN, + EMC_AR2PDEN, + EMC_RW2PDEN, + EMC_TXSR, + EMC_TCKE, + EMC_TFAW, + EMC_TRPAB, + EMC_TCLKSTABLE, + EMC_TCLKSTOP, + EMC_TREFBW, + EMC_QUSE_EXTRA, + EMC_FBIO_CFG6, + EMC_ODT_WRITE, + EMC_ODT_READ, + EMC_FBIO_CFG5, + EMC_CFG_DIG_DLL, + EMC_DLL_XFORM_DQS, + EMC_DLL_XFORM_QUSE, + EMC_ZCAL_REF_CNT, + EMC_ZCAL_WAIT_CNT, + EMC_AUTO_CAL_INTERVAL, + EMC_CFG_CLKTRIM_0, + EMC_CFG_CLKTRIM_1, + EMC_CFG_CLKTRIM_2, +}; + +struct emc_timing { + unsigned long rate; + u32 emc_registers_data[ARRAY_SIZE(emc_timing_registers)]; +}; + +struct tegra_emc { + struct device *dev; + struct notifier_block clk_nb; + struct clk *backup_clk; + struct clk *emc_mux; + struct clk *pll_m; + struct clk *clk; + void __iomem *regs; + + struct completion clk_handshake_complete; + int irq; + + struct emc_timing *timings; + unsigned int num_timings; +}; + +static irqreturn_t tegra_emc_isr(int irq, void *data) +{ + struct tegra_emc *emc = data; + u32 intmask, status; + + if (completion_done(&emc->clk_handshake_complete)) + return IRQ_NONE; + + intmask = EMC_CLKCHANGE_COMPLETE_INT; + + status = readl_relaxed(emc->regs + EMC_INTSTATUS) & intmask; + if (!status) + return IRQ_NONE; + + writel_relaxed(status, emc->regs + EMC_INTSTATUS); + + complete(&emc->clk_handshake_complete); + + return IRQ_HANDLED; +} + +static struct emc_timing *tegra_emc_find_timing(struct tegra_emc *emc, + unsigned long rate) +{ + struct emc_timing *timing = NULL; + unsigned int i; + + for (i = 0; i < emc->num_timings; i++) { + if (emc->timings[i].rate >= rate) { + timing = &emc->timings[i]; + break; + } + } + + if (!timing) { + dev_err(emc->dev, "no timing for rate %lu\n", rate); + return NULL; + } + + return timing; +} + +static int emc_prepare_timing_change(struct tegra_emc *emc, unsigned long rate) +{ + struct emc_timing *timing = tegra_emc_find_timing(emc, rate); + unsigned int i; + + if (!timing) + return -ENOENT; + + dev_dbg(emc->dev, "%s: timing rate %lu emc rate %lu\n", + __func__, timing->rate, rate); + + /* program shadow registers */ + for (i = 0; i < ARRAY_SIZE(timing->emc_registers_data); i++) + writel(timing->emc_registers_data[i], + emc->regs + emc_timing_registers[i]); + + /* read last-written register to wait until programming has settled */ + readl(emc->regs + emc_timing_registers[i - 1]); + + if (emc->irq < 0) + writel(EMC_CLKCHANGE_COMPLETE_INT, emc->regs + EMC_INTMASK); + else + reinit_completion(&emc->clk_handshake_complete); + + return 0; +} + +static int emc_complete_timing_change(struct tegra_emc *emc, bool flush) +{ + long timeout; + u32 value; + int err; + + dev_dbg(emc->dev, "%s: flush %d\n", __func__, flush); + + if (flush) { + /* manually initiate memory timings update */ + writel(EMC_TIMING_UPDATE, emc->regs + EMC_TIMING_CONTROL); + return 0; + } + + if (emc->irq < 0) { + /* poll interrupt status if IRQ isn't available */ + err = readl_relaxed_poll_timeout(emc->regs + EMC_INTSTATUS, + value, value & EMC_CLKCHANGE_COMPLETE_INT, + 1, 100); + if (err) { + dev_err(emc->dev, "EMC handshake failed\n"); + return -EIO; + } + + return 0; + } + + timeout = wait_for_completion_timeout(&emc->clk_handshake_complete, + usecs_to_jiffies(100)); + if (timeout == 0) { + dev_err(emc->dev, "EMC handshake failed\n"); + return -EIO; + } else if (timeout < 0) { + dev_err(emc->dev, "failed to wait for EMC handshake: %ld\n", + timeout); + return timeout; + } + + return 0; +} + +static int load_one_timing_from_dt(struct tegra_emc *emc, + struct emc_timing *timing, + struct device_node *node) +{ + u32 rate; + int err; + + if (!of_device_is_compatible(node, "nvidia,tegra20-emc-table")) { + dev_err(emc->dev, "incompatible DT node \"%s\"\n", + node->name); + return -EINVAL; + } + + err = of_property_read_u32(node, "clock-frequency", &rate); + if (err) { + dev_err(emc->dev, "timing %s: failed to read rate: %d\n", + node->name, err); + return err; + } + + err = of_property_read_u32_array(node, "nvidia,emc-registers", + timing->emc_registers_data, + ARRAY_SIZE(emc_timing_registers)); + if (err) { + dev_err(emc->dev, + "timing %s: failed to read emc timing data: %d\n", + node->name, err); + return err; + } + + /* + * The EMC clock rate is twice the bus rate, and the bus rate is + * measured in kHz. + */ + timing->rate = rate * 2 * 1000; + + dev_dbg(emc->dev, "%s: emc rate %ld\n", __func__, timing->rate); + + return 0; +} + +static int cmp_timings(const void *_a, const void *_b) +{ + const struct emc_timing *a = _a; + const struct emc_timing *b = _b; + + if (a->rate < b->rate) + return -1; + else if (a->rate == b->rate) + return 0; + else + return 1; +} + +static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc, + struct device_node *node) +{ + struct device_node *child; + struct emc_timing *timing; + int child_count; + int err; + + child_count = of_get_child_count(node); + if (!child_count) + return -ENOENT; + + emc->timings = devm_kcalloc(emc->dev, child_count, sizeof(*timing), + GFP_KERNEL); + if (!emc->timings) + return -ENOMEM; + + emc->num_timings = child_count; + timing = emc->timings; + + for_each_child_of_node(node, child) { + err = load_one_timing_from_dt(emc, timing++, child); + if (err) { + of_node_put(child); + return err; + } + } + + sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings, + NULL); + + return 0; +} + +static struct device_node * +tegra_emc_find_node_by_ram_code(struct device_node *node, u32 ram_code) +{ + struct device_node *np; + int err; + + for_each_child_of_node(node, np) { + u32 value; + + err = of_property_read_u32(np, "nvidia,ram-code", &value); + if (err || value != ram_code) + continue; + + return np; + } + + return NULL; +} + +static int tegra_emc_clk_change_notify(struct notifier_block *nb, + unsigned long msg, void *data) +{ + struct tegra_emc *emc = container_of(nb, struct tegra_emc, clk_nb); + struct clk_notifier_data *cnd = data; + int err; + + switch (msg) { + case PRE_RATE_CHANGE: + err = emc_prepare_timing_change(emc, cnd->new_rate); + break; + + case ABORT_RATE_CHANGE: + err = emc_prepare_timing_change(emc, cnd->old_rate); + if (err) + break; + + err = emc_complete_timing_change(emc, true); + break; + + case POST_RATE_CHANGE: + err = emc_complete_timing_change(emc, false); + break; + + default: + return NOTIFY_DONE; + } + + return notifier_from_errno(err); +} + +static void emc_setup_hw(struct tegra_emc *emc) +{ + u32 value; + + /* allow EMC and CAR to handshake on PLL divider/source changes */ + value = readl_relaxed(emc->regs + EMC_CFG_2); + value |= EMC_CLKCHANGE_REQ_ENABLE; + writel(value, emc->regs + EMC_CFG_2); + + /* initialize interrupt */ + writel(EMC_CLKCHANGE_COMPLETE_INT, emc->regs + EMC_INTMASK); + writel(EMC_CLKCHANGE_COMPLETE_INT, emc->regs + EMC_INTSTATUS); +} + +static int emc_init(struct tegra_emc *emc, unsigned long rate) +{ + int err; + + err = clk_set_parent(emc->emc_mux, emc->backup_clk); + if (err) { + dev_err(emc->dev, + "failed to reparent to backup source: %d\n", err); + return err; + } + + err = clk_set_rate(emc->pll_m, rate); + if (err) + dev_err(emc->dev, + "failed to change pll_m rate: %d\n", err); + + err = clk_set_parent(emc->emc_mux, emc->pll_m); + if (err) { + dev_err(emc->dev, + "failed to reparent to pll_m: %d\n", err); + return err; + } + + return 0; +} + +static int tegra_emc_probe(struct platform_device *pdev) +{ + struct device_node *np; + struct tegra_emc *emc; + struct resource *res; + u32 ram_code; + int err; + + emc = devm_kzalloc(&pdev->dev, sizeof(*emc), GFP_KERNEL); + if (!emc) + return -ENOMEM; + + emc->dev = &pdev->dev; + + ram_code = tegra_read_ram_code(); + + np = tegra_emc_find_node_by_ram_code(pdev->dev.of_node, ram_code); + if (!np) { + dev_info(&pdev->dev, + "no memory timings for RAM code %u found in DT\n", + ram_code); + return -ENOENT; + } + + err = tegra_emc_load_timings_from_dt(emc, np); + of_node_put(np); + if (err) + return err; + + if (emc->num_timings == 0) { + dev_err(&pdev->dev, + "no memory timings for RAM code %u registered\n", + ram_code); + return -ENOENT; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + emc->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(emc->regs)) + return PTR_ERR(emc->regs); + + emc_setup_hw(emc); + + emc->irq = platform_get_irq(pdev, 0); + if (emc->irq < 0) { + dev_warn(&pdev->dev, "interrupt not specified\n"); + dev_warn(&pdev->dev, "continuing, but please update your DT\n"); + } else { + init_completion(&emc->clk_handshake_complete); + + err = devm_request_irq(&pdev->dev, emc->irq, tegra_emc_isr, 0, + dev_name(&pdev->dev), emc); + if (err < 0) { + dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", + emc->irq, err); + return err; + } + } + + emc->pll_m = clk_get_sys(NULL, "pll_m"); + if (IS_ERR(emc->pll_m)) { + err = PTR_ERR(emc->pll_m); + dev_err(&pdev->dev, "failed to get pll_m: %d\n", err); + return -EPROBE_DEFER; + } + + emc->backup_clk = clk_get_sys(NULL, "pll_p"); + if (IS_ERR(emc->backup_clk)) { + err = PTR_ERR(emc->backup_clk); + dev_err(&pdev->dev, "failed to get pll_p: %d\n", err); + goto put_pll_m; + } + + emc->clk = clk_get_sys(NULL, "emc"); + if (IS_ERR(emc->clk)) { + err = PTR_ERR(emc->clk); + dev_err(&pdev->dev, "failed to get emc: %d\n", err); + goto put_backup; + } + + emc->emc_mux = clk_get_parent(emc->clk); + if (IS_ERR(emc->emc_mux)) { + err = PTR_ERR(emc->emc_mux); + dev_err(&pdev->dev, "failed to get emc_mux: %d\n", err); + goto put_emc; + } + + emc->clk_nb.notifier_call = tegra_emc_clk_change_notify; + + err = clk_notifier_register(emc->clk, &emc->clk_nb); + if (err) { + dev_err(&pdev->dev, "failed to register clk notifier: %d\n", + err); + goto put_emc; + } + + /* set DRAM clock rate to maximum */ + err = emc_init(emc, emc->timings[emc->num_timings - 1].rate); + if (err) { + dev_err(&pdev->dev, "failed to initialize clk rate: %d\n", + err); + goto unreg_notifier; + } + + return 0; + +unreg_notifier: + clk_notifier_unregister(emc->emc_mux, &emc->clk_nb); +put_emc: + clk_put(emc->clk); +put_backup: + clk_put(emc->backup_clk); +put_pll_m: + clk_put(emc->pll_m); + + return err; +} + +static const struct of_device_id tegra_emc_of_match[] = { + { .compatible = "nvidia,tegra20-emc", }, + {}, +}; + +static struct platform_driver tegra_emc_driver = { + .probe = tegra_emc_probe, + .driver = { + .name = "tegra20-emc", + .of_match_table = tegra_emc_of_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init tegra_emc_init(void) +{ + return platform_driver_register(&tegra_emc_driver); +} +subsys_initcall(tegra_emc_init);