Received: by 2002:a25:8b91:0:0:0:0:0 with SMTP id j17csp2855414ybl; Thu, 19 Dec 2019 23:04:47 -0800 (PST) X-Google-Smtp-Source: APXvYqwHBSLMfwEsaMKGqtLCIhBWTgFcOZmYmYV+JbN7uO3yWssXdq1gpRZy5mOAPoo8yZ/GIX9u X-Received: by 2002:a9d:75da:: with SMTP id c26mr13395519otl.40.1576825487112; Thu, 19 Dec 2019 23:04:47 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1576825487; cv=none; d=google.com; s=arc-20160816; b=KIpwJhfeNkRTwcDy8ZlBEzMmi8FSmpTnxrAaN8voufRFcXgEBKdaUzSO47nOvapexQ 2wdff4ABSaPhrqkHxik0D6HJcY65SFsdKFFCUaAqWb+017HGZpiJaoRvSdLwYphZKin1 0e7PUkni+48GKP9M5muCy68zEDxn5UloeSgqF8p2duQJ44rdNMJO/LHxfMz2H5wQ7H6h gJBlmuO3Y81KPzGnR+Jce9iRjvoJdecafnSS1dT8ESAvbRpda7wGNdO6QSLs9PyVIzCA 7etKhF646/0L/sbtAZj6Qrm9raDmWXDMrbtZh8MOaqc7pvQHvvSddCrzZWr9CNJ7TKBq i8DA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding :content-language:in-reply-to:mime-version:user-agent:date :message-id:references:cc:to:from:subject; bh=j4Dx8dwTsx1BXnRHo4oEcBpdHGecYo9IbPUlMxTKKXU=; b=otqF2bOHVeaLWEG50rdL3kM2Ca501u34yj5OUJgzi4ers6kExPpl+7WD51bnj81Glx IML3Cg/nYJyYbbBvFyebRp7E/9MWMSfgOoBMORtdSPWo+Lt5PCSVo/1AMFLKZwe1djOg WKLngD5xPszsZXOUCiP9EHjuNsWmH4hE96m2irCHCkdC8CKxGcfd1oFIuTaYIXMiHzzq b44arDxmUq+EX6bb3TnQRC3cQ+nCmR6UxC9X0q/DyJiPg6SfWcO1V1ARHRpxHFGwsy3d YF8labGwsIta4SAI8Z9JKP2V6sQbWqCwdZLcd+gohvF1Zy3ycXez1+Hb5EjnBjrDNJxA e51w== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id r12si4509629otq.156.2019.12.19.23.04.36; Thu, 19 Dec 2019 23:04:47 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727328AbfLTHDX (ORCPT + 99 others); Fri, 20 Dec 2019 02:03:23 -0500 Received: from mail-sz.amlogic.com ([211.162.65.117]:33863 "EHLO mail-sz.amlogic.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725874AbfLTHDW (ORCPT ); Fri, 20 Dec 2019 02:03:22 -0500 Received: from [10.28.39.99] (10.28.39.99) by mail-sz.amlogic.com (10.28.11.5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.1591.10; Fri, 20 Dec 2019 15:03:52 +0800 Subject: Re: [PATCH v4 2/6] clk: meson: add support for A1 PLL clock ops From: Jian Hu To: Jerome Brunet , Neil Armstrong CC: Kevin Hilman , Rob Herring , Martin Blumenstingl , Michael Turquette , Stephen Boyd , Qiufang Dai , Jianxin Pan , Victor Wan , Chandle Zou , , , , , References: <20191206074052.15557-1-jian.hu@amlogic.com> <20191206074052.15557-3-jian.hu@amlogic.com> <1j8snhluhg.fsf@starbuckisacylon.baylibre.com> <741284be-2ae8-1102-22bc-c510e822c883@amlogic.com> <1jk16vb8qm.fsf@starbuckisacylon.baylibre.com> <0bc6176f-c0b8-5c31-4c6b-d3686eefe56e@amlogic.com> Message-ID: <627a8d8b-f049-4cdd-6dd0-5c5acc58a90c@amlogic.com> Date: Fri, 20 Dec 2019 15:03:52 +0800 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:60.0) Gecko/20100101 Thunderbird/60.9.1 MIME-Version: 1.0 In-Reply-To: <0bc6176f-c0b8-5c31-4c6b-d3686eefe56e@amlogic.com> Content-Type: text/plain; charset="utf-8"; format=flowed Content-Language: en-US Content-Transfer-Encoding: 8bit X-Originating-IP: [10.28.39.99] X-ClientProxiedBy: mail-sz.amlogic.com (10.28.11.5) To mail-sz.amlogic.com (10.28.11.5) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi jerome On 2019/12/18 16:37, Jian Hu wrote: > > > On 2019/12/17 17:29, Jerome Brunet wrote: >> >> On Tue 17 Dec 2019 at 09:41, Jian Hu wrote: >> >>> On 2019/12/12 18:16, Jerome Brunet wrote: >>>> >>>> On Fri 06 Dec 2019 at 08:40, Jian Hu wrote: >>>> >>>>> The A1 PLL design is different with previous SoCs. The PLL >>>>> internal analog modules Power-on sequence is different >>>>> with previous, and thus requires a strict register sequence to >>>>> enable the PLL. >>>>> >>>>> Signed-off-by: Jian Hu >>>>> --- >>>>>    drivers/clk/meson/clk-pll.c | 21 +++++++++++++++++++++ >>>>>    drivers/clk/meson/clk-pll.h |  1 + >>>>>    drivers/clk/meson/parm.h    |  1 + >>>>>    3 files changed, 23 insertions(+) >>>>> >>>>> diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c >>>>> index ddb1e5634739..4aff31a51589 100644 >>>>> --- a/drivers/clk/meson/clk-pll.c >>>>> +++ b/drivers/clk/meson/clk-pll.c >>>>> @@ -318,6 +318,23 @@ static int meson_clk_pll_enable(struct clk_hw >>>>> *hw) >>>>>        struct clk_regmap *clk = to_clk_regmap(hw); >>>>>        struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); >>>>>    +    /* >>>>> +     * The A1 design is different with previous SoCs.The PLL >>>>> +     * internal analog modules Power-on sequence is different with >>>>> +     * previous, and thus requires a strict register sequence to >>>>> +     * enable the PLL. >>>> >>>> The code does something more, not completly different. This comment is >>>> not aligned with what the code does >>> ok, I will correct the comment. >>>> >>>>> +     */ >>>>> +    if (MESON_PARM_APPLICABLE(&pll->current_en)) { >>>>> +        /* Enable the pll */ >>>>> +        meson_parm_write(clk->map, &pll->en, 1); >>>>> +        udelay(10); >>>>> +        /* Enable the pll self-adaption module current */ >>>>> +        meson_parm_write(clk->map, &pll->current_en, 1); >>>>> +        udelay(40); >>>>> +        meson_parm_write(clk->map, &pll->rst, 1); >>>>> +        meson_parm_write(clk->map, &pll->rst, 0); >>>> >>>> Here you enable the PLL and self adaptation module then reset the PLL. >>>> However: >>>> #1 when you enter this function, the PLL should already by in reset >>>> and disabled >>>> #2 the code after that will reset the PLL again >>> For A1 PLLs, There is no reset bit, It will not reset the PLL. >>> And in V2, you mentioned PARM 'rst' can be used for one toggling, And >>> 'rst' >>> is used for BIT(6) in CTRL2. >>> >> >> oh my ! What is it then ? Why do you need to toggle it ? What does is >> do ? >> > The PLL enable flow: >      step1: enable the PLL >      step2: enable the self adaptation module >      step3: reset the lock detect module, let the lock detect module >            work,And then the PLL will work. > > Toggle the bit 6 in CTRL2 can reset the lock detect module. #1 I intend to introduce a new PARM 'l_detect', and the meson_clk_pll_enable is blow. Please help to review it. static int meson_clk_pll_enable(struct clk_hw *hw) { struct clk_regmap *clk = to_clk_regmap(hw); struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); /* do nothing if the PLL is already enabled */ if (clk_hw_is_enabled(hw)) return 0; /* * Compared with the previous SoCs, self-adaption module current * is newly added, keep the new power-on sequence to enable the * PLL. */ if (MESON_PARM_APPLICABLE(&pll->current_en)) { /* Enable the pll */ meson_parm_write(clk->map, &pll->en, 1); udelay(10); /* Enable the pll self-adaption module current */ meson_parm_write(clk->map, &pll->current_en, 1); udelay(40); /* Enable lock detect module */ meson_parm_write(clk->map, &pll->l_detect, 1); meson_parm_write(clk->map, &pll->l_detect, 0); goto out; } /* Make sure the pll is in reset */ meson_parm_write(clk->map, &pll->rst, 1); /* Enable the pll */ meson_parm_write(clk->map, &pll->en, 1); /* Take the pll out reset */ meson_parm_write(clk->map, &pll->rst, 0); out: if (meson_clk_pll_wait_lock(hw)) return -EIO; return 0; } #2 Add check for PARM 'rst' when writing to it, the same with frac. if (MESON_PARM_APPLICABLE(&pll->rst)) meson_parm_write(clk->map, &pll->rst, 1); And I have tested it for it, The periphs and hifi pll works well. Or any good idea about it? >>> Quote V2 the HIFI PLL init_regs definition: >>> >>> >>> +static const struct reg_sequence a1_hifi_init_regs[] = { >>> +    { .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x01800000 }, >>> +    { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 }, >>> +    { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x100a1100 }, >>> +    { .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x00302000 }, >>> +    { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f18440 }, >>> +    { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x11f18440, .delay_us = >>> 10 }, >>> +    { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x15f18440, .delay_us = >>> 40 }, >>> +    { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001140 }, >>> +    { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 }, >>> +}; >>> >>> So maybe another new PARM should be defined to avoid the ambiguity. >>> What do you think about it? >> >> This is not the point of my comment Jian ! >> >> I'm assuming here that you have tested your v4 before sending and that >> it work (hopefully) >> > Yes, it works wells. I have tested the drivers before sending every > patchset version. >> The fact is that with this code, when disabled the bit behind rst >> (whatever it is) is set. So when you get to enable the bit is already >> set. >> The code you sent does the same as the snip I gave you in the reply. >> >> Now, if your PLL is THAT different, maybe it would be best if you could >> clearly explain how it works, what bit should be set and why. Then we >> will be able to figure out how the driver has to be restructured. >> > the same as 'The PLL enable flow' above >>> >>>> >>>> So if what you submited works, inserting the following should >>>> accomplish >>>> the same thing: >>>> >>>> ---8<--- >>>> diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c >>>> index 489092dde3a6..9b38df0a7682 100644 >>>> --- a/drivers/clk/meson/clk-pll.c >>>> +++ b/drivers/clk/meson/clk-pll.c >>>> @@ -330,6 +330,13 @@ static int meson_clk_pll_enable(struct clk_hw *hw) >>>>           /* Enable the pll */ >>>>           meson_parm_write(clk->map, &pll->en, 1); >>>> >>>> +       if (MESON_PARM_APPLICABLE(&pll->current_en)) { >>>> +               udelay(10); >>>> +               /* Enable the pll self-adaption module current */ >>>> +               meson_parm_write(clk->map, &pll->current_en, 1); >>>> +               udelay(40); >>>> +       } >>>> + >>>>           /* Take the pll out reset */ >>>>           meson_parm_write(clk->map, &pll->rst, 0); >>>> --->8--- >>>> >>>> >>>> >>>> >>>>> +    } >>>>> + >>>>>        /* do nothing if the PLL is already enabled */ >>>>>        if (clk_hw_is_enabled(hw)) >>>>>            return 0; >>>> >>>> In any case, nothing should be done on the clock before this check >>>> otherwise you might just break the clock >>>> >>> OK, I will put the enabled check ahead. >>>>> @@ -347,6 +364,10 @@ static void meson_clk_pll_disable(struct >>>>> clk_hw *hw) >>>>>          /* Disable the pll */ >>>>>        meson_parm_write(clk->map, &pll->en, 0); >>>>> + >>>>> +    /* Disable PLL internal self-adaption module current */ >>>>> +    if (MESON_PARM_APPLICABLE(&pll->current_en)) >>>>> +        meson_parm_write(clk->map, &pll->current_en, 0); >>>>>    } >>>>>      static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned >>>>> long >>>>> rate, >>>>> diff --git a/drivers/clk/meson/clk-pll.h b/drivers/clk/meson/clk-pll.h >>>>> index 367efd0f6410..30f039242a65 100644 >>>>> --- a/drivers/clk/meson/clk-pll.h >>>>> +++ b/drivers/clk/meson/clk-pll.h >>>>> @@ -36,6 +36,7 @@ struct meson_clk_pll_data { >>>>>        struct parm frac; >>>>>        struct parm l; >>>>>        struct parm rst; >>>>> +    struct parm current_en; >>>>>        const struct reg_sequence *init_regs; >>>>>        unsigned int init_count; >>>>>        const struct pll_params_table *table; >>>>> diff --git a/drivers/clk/meson/parm.h b/drivers/clk/meson/parm.h >>>>> index 3c9ef1b505ce..c53fb26577e3 100644 >>>>> --- a/drivers/clk/meson/parm.h >>>>> +++ b/drivers/clk/meson/parm.h >>>>> @@ -20,6 +20,7 @@ >>>>>        (((reg) & CLRPMASK(width, shift)) | ((val) << (shift))) >>>>>      #define MESON_PARM_APPLICABLE(p)        (!!((p)->width)) >>>>> +#define MESON_PARM_CURRENT(p)            (!!((p)->width)) >>>> >>>> Why do we need that ? >>> OK, I will remove it ,and use 'MESON_PARM_APPLICABLE' instead >>>> >>>>>      struct parm { >>>>>        u16    reg_off; >>>> >>>> . >>>> >> >> . >>