From: Lin Huang <hidden> Date: 2016-06-03 09:55:39
On new rockchip platform(rk3399 etc), there have dcf controller to
do ddr frequency scaling, and this controller will implement in
arm-trust-firmware. We add a special clock-type to handle that.
Signed-off-by: Lin Huang <redacted>
---
Changes in v1:
- None
drivers/clk/rockchip/Makefile | 1 +
drivers/clk/rockchip/clk-ddr.c | 147 +++++++++++++++++++++++++++++++++++++++++
drivers/clk/rockchip/clk.c | 9 +++
drivers/clk/rockchip/clk.h | 27 ++++++++
4 files changed, 184 insertions(+)
create mode 100644 drivers/clk/rockchip/clk-ddr.c
From: Lin Huang <hidden> Date: 2016-06-03 09:55:47
add ddrc clock setting, so we can do ddr frequency
scaling on rk3399 platform in future.
Signed-off-by: Lin Huang <redacted>
---
Changes in v1:
- remove ddrc source CLK_IGNORE_UNUSED flag, Suggestion by Doug
- move clk_ddrc and clk_ddrc_dpll_src to critical, Suggestion by Doug
drivers/clk/rockchip/clk-rk3399.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
From: Lin Huang <hidden> Date: 2016-06-03 09:55:54
on rk3399 platform, there is dfi conroller can monitor
ddr load, base on this result, we can do ddr freqency
scaling.
Signed-off-by: Lin Huang <redacted>
---
Changes in v1:
- NOne
drivers/devfreq/event/Kconfig | 7 +
drivers/devfreq/event/Makefile | 1 +
drivers/devfreq/event/rockchip-dfi.c | 265 +++++++++++++++++++++++++++++++++++
3 files changed, 273 insertions(+)
create mode 100644 drivers/devfreq/event/rockchip-dfi.c
From: Lin Huang <hidden> Date: 2016-06-03 09:56:00
when in ddr frequency scaling process, vop can not do
enable or disable operate, since dcf will base on vop vblank
time to do frequency scaling and need to get vop irq if there
have vop enabled. So need register to dmc notifier, and we can
get the dmc status.
Signed-off-by: Lin Huang <redacted>
---
Changes in v1:
- use wait_event instead usleep, Suggestion by Derek
drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 43 +++++++++++++++++++++++++++--
1 file changed, 41 insertions(+), 2 deletions(-)
@@ -0,0 +1,337 @@+/*+*Copyright(c)2016,FuzhouRockchipElectronicsCo.,Ltd+*Author:LinHuang<hl@rock-chips.com>+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodifyit+*underthetermsandconditionsoftheGNUGeneralPublicLicense,+*version2,aspublishedbytheFreeSoftwareFoundation.+*+*Thisprogramisdistributedinthehopeitwillbeuseful,butWITHOUT+*ANYWARRANTY;withouteventheimpliedwarrantyofMERCHANTABILITYor+*FITNESSFORAPARTICULARPURPOSE.SeetheGNUGeneralPublicLicensefor+*moredetails.+*/++#include<linux/clk.h>+#include<linux/completion.h>+#include<linux/delay.h>+#include<linux/devfreq.h>+#include<linux/devfreq-event.h>+#include<linux/interrupt.h>+#include<linux/module.h>+#include<linux/of.h>+#include<linux/platform_device.h>+#include<linux/pm_opp.h>+#include<linux/regulator/consumer.h>+#include<linux/rwsem.h>+#include<linux/suspend.h>+#include<linux/syscore_ops.h>++#include<soc/rockchip/rockchip_dmc.h>++structrk3399_dmcfreq{+structdevice*dev;+structdevfreq*devfreq;+structdevfreq_simple_ondemand_dataondemand_data;+structclk*dmc_clk;+structcompletiondcf_hold_completion;+structdevfreq_event_dev*edev;+structmutexlock;+structnotifier_blockdmc_nb;+intirq;+structregulator*vdd_center;+unsignedlongrate,target_rate;+unsignedlongvolt,target_volt;+};++staticintrk3399_dmcfreq_target(structdevice*dev,unsignedlong*freq,+u32flags)+{+structplatform_device*pdev=container_of(dev,structplatform_device,+dev);+structrk3399_dmcfreq*dmcfreq=platform_get_drvdata(pdev);+structdev_pm_opp*opp;+unsignedlongold_clk_rate=dmcfreq->rate;+unsignedlongtarget_volt,target_rate;+interr;++rcu_read_lock();+opp=devfreq_recommended_opp(dev,freq,flags);+if(IS_ERR(opp)){+rcu_read_unlock();+returnPTR_ERR(opp);+}+target_rate=dev_pm_opp_get_freq(opp);+target_volt=dev_pm_opp_get_voltage(opp);+opp=devfreq_recommended_opp(dev,&dmcfreq->rate,flags);+if(IS_ERR(opp)){+rcu_read_unlock();+returnPTR_ERR(opp);+}+dmcfreq->volt=dev_pm_opp_get_voltage(opp);+rcu_read_unlock();++if(dmcfreq->rate==target_rate)+return0;++mutex_lock(&dmcfreq->lock);++/*+*iffrequencyscalingfromlowtohigh,adjustvoltagefirst;+*iffrequencyscalingfromhightolow,adjusetfrequencyfirst;+*/+if(old_clk_rate<target_rate){+err=regulator_set_voltage(dmcfreq->vdd_center,target_volt,+target_volt);+if(err){+dev_err(dev,"Unable to set vol %lu\n",target_volt);+gotoout;+}+}++dmc_event(DMCFREQ_ADJUST);+reinit_completion(&dmcfreq->dcf_hold_completion);+err=clk_set_rate(dmcfreq->dmc_clk,target_rate);+if(err){+dev_err(dev,+"Unable to set freq %lu. Current freq %lu. Error %d\n",+target_rate,old_clk_rate,err);+regulator_set_voltage(dmcfreq->vdd_center,dmcfreq->volt,+dmcfreq->volt);+dmc_event(DMCFREQ_FINISH);+gotoout;+}++/* wait until bcf irq happen, it means freq scaling finish in bl31 */+wait_for_completion(&dmcfreq->dcf_hold_completion);+dmc_event(DMCFREQ_FINISH);++/*+*checktheratewegetwhetheriscorrect+*inbl31dcf,thereonlytworesultwewillget,+*1.ddrfrequencyscalingfail,westillgettheoldrate+*2,ddrfrequencyscalingsucessful,wegettherateweset+*/+dmcfreq->rate=clk_get_rate(dmcfreq->dmc_clk);++/* do not get the right rate, set voltage to old value */+if(dmcfreq->rate!=target_rate){+dev_err(dev,"get wrong ddr frequency, Request freq %lu,\+Currentfreq%lu\n", target_rate, dmcfreq->rate);+regulator_set_voltage(dmcfreq->vdd_center,dmcfreq->volt,+dmcfreq->volt);+}elseif(old_clk_rate>target_rate)+err=regulator_set_voltage(dmcfreq->vdd_center,target_volt,+target_volt);+if(err)+dev_err(dev,"Unable to set vol %lu\n",target_volt);++out:+mutex_unlock(&dmcfreq->lock);+returnerr;+}++staticintrk3399_dmcfreq_get_dev_status(structdevice*dev,+structdevfreq_dev_status*stat)+{+structplatform_device*pdev=container_of(dev,structplatform_device,+dev);+structrk3399_dmcfreq*dmcfreq=platform_get_drvdata(pdev);+structdevfreq_event_dataedata;++devfreq_event_get_event(dmcfreq->edev,&edata);++stat->current_frequency=dmcfreq->rate;+stat->busy_time=edata.load_count;+stat->total_time=edata.total_count;++return0;+}++staticintrk3399_dmcfreq_get_cur_freq(structdevice*dev,unsignedlong*freq)+{+structplatform_device*pdev=container_of(dev,structplatform_device,+dev);+structrk3399_dmcfreq*dmcfreq=platform_get_drvdata(pdev);++*freq=dmcfreq->rate;++return0;+}++staticvoidrk3399_dmcfreq_exit(structdevice*dev)+{+structplatform_device*pdev=container_of(dev,structplatform_device,+dev);+structrk3399_dmcfreq*dmcfreq=platform_get_drvdata(pdev);++devfreq_unregister_opp_notifier(dev,dmcfreq->devfreq);+}++staticstructdevfreq_dev_profilerk3399_devfreq_dmc_profile={+.polling_ms=200,+.target=rk3399_dmcfreq_target,+.get_dev_status=rk3399_dmcfreq_get_dev_status,+.get_cur_freq=rk3399_dmcfreq_get_cur_freq,+.exit=rk3399_dmcfreq_exit,+};++static__maybe_unusedintrk3399_dmcfreq_suspend(structdevice*dev)+{+rockchip_dmc_disable();+return0;+}++static__maybe_unusedintrk3399_dmcfreq_resume(structdevice*dev)+{+rockchip_dmc_enable();+return0;+}++staticSIMPLE_DEV_PM_OPS(rk3399_dmcfreq_pm,rk3399_dmcfreq_suspend,+rk3399_dmcfreq_resume);++staticintrk3399_dmc_enable_notify(structnotifier_block*nb,+unsignedlongevent,void*data)+{+structrk3399_dmcfreq*dmcfreq=+container_of(nb,structrk3399_dmcfreq,dmc_nb);+unsignedlongfreq=ULONG_MAX;++if(event==DMC_ENABLE){+devfreq_event_enable_edev(dmcfreq->edev);+devfreq_resume_device(dmcfreq->devfreq);+returnNOTIFY_OK;+}elseif(event==DMC_DISABLE){+devfreq_event_disable_edev(dmcfreq->edev);+devfreq_suspend_device(dmcfreq->devfreq);++/* when disable dmc, set sdram to max frequency */+rk3399_dmcfreq_target(dmcfreq->dev,&freq,0);+returnNOTIFY_OK;+}++returnNOTIFY_DONE;+}++staticirqreturn_trk3399_dmc_irq(intirq,void*dev_id)+{+structrk3399_dmcfreq*dmcfreq=dev_id;++complete(&dmcfreq->dcf_hold_completion);++returnIRQ_HANDLED;+}++staticintrk3399_dmcfreq_probe(structplatform_device*pdev)+{+structdevice*dev=&pdev->dev;+structrk3399_dmcfreq*data;+intret,irq;+structdevice_node*np=pdev->dev.of_node;++irq=platform_get_irq(pdev,0);+if(irq<0){+dev_err(&pdev->dev,"no dmc irq resource\n");+return-EINVAL;+}++data=devm_kzalloc(dev,sizeof(structrk3399_dmcfreq),GFP_KERNEL);+if(!data)+return-ENOMEM;++mutex_init(&data->lock);++data->vdd_center=devm_regulator_get(dev,"center");+if(IS_ERR(data->vdd_center)){+dev_err(dev,"Cannot get the regulator \"center\"\n");+returnPTR_ERR(data->vdd_center);+}++data->dmc_clk=devm_clk_get(dev,"dmc_clk");+if(IS_ERR(data->dmc_clk)){+dev_err(dev,"Cannot get the clk dmc_clk\n");+returnPTR_ERR(data->dmc_clk);+};++data->edev=devfreq_event_get_edev_by_phandle(dev,0);+if(IS_ERR(data->edev))+return-EPROBE_DEFER;++ret=devfreq_event_enable_edev(data->edev);+if(ret<0){+dev_err(dev,"failed to enable devfreq-event devices\n");+returnret;+}++/*+*Weaddadevfreqdrivertoourparentsinceithasadevicetreenode+*withoperatingpoints.+*/+if(dev_pm_opp_of_add_table(dev)){+dev_err(dev,"Invalid operating-points in device tree.\n");+return-EINVAL;+}++of_property_read_u32(np,"upthreshold",+&data->ondemand_data.upthreshold);++of_property_read_u32(np,"downdifferential",+&data->ondemand_data.downdifferential);++data->devfreq=devfreq_add_device(dev,+&rk3399_devfreq_dmc_profile,+"simple_ondemand",+&data->ondemand_data);+if(IS_ERR(data->devfreq))+returnPTR_ERR(data->devfreq);++devfreq_register_opp_notifier(dev,data->devfreq);++data->dmc_nb.notifier_call=rk3399_dmc_enable_notify;+dmc_register_notifier(&data->dmc_nb);++init_completion(&data->dcf_hold_completion);++data->irq=irq;+ret=devm_request_irq(dev,irq,rk3399_dmc_irq,0,+dev_name(dev),data);+if(ret){+dev_err(dev,"failed to request dmc irq: %d\n",ret);+returnret;+}++data->dev=dev;+platform_set_drvdata(pdev,data);++return0;+}++staticintrk3399_dmcfreq_remove(structplatform_device*pdev)+{+structrk3399_dmcfreq*dmcfreq=platform_get_drvdata(pdev);++devfreq_remove_device(dmcfreq->devfreq);+regulator_put(dmcfreq->vdd_center);++return0;+}++staticconststructof_device_idrk3399dmc_devfreq_of_match[]={+{.compatible="rockchip,rk3399-dmc"},+{},+};++staticstructplatform_driverrk3399_dmcfreq_driver={+.probe=rk3399_dmcfreq_probe,+.remove=rk3399_dmcfreq_remove,+.driver={+.name="rk3399-dmc-freq",+.pm=&rk3399_dmcfreq_pm,+.of_match_table=rk3399dmc_devfreq_of_match,+},+};+module_platform_driver(rk3399_dmcfreq_driver);++MODULE_LICENSE("GPL v2");+MODULE_DESCRIPTION("RK3399 dmcfreq driver with devfreq framework");
@@ -0,0 +1,143 @@+/*+*Copyright(c)2016,FuzhouRockchipElectronicsCo.,Ltd+*Author:LinHuang<hl@rock-chips.com>+*Baseon:https://chromium-review.googlesource.com/#/c/231477/+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodifyit+*underthetermsandconditionsoftheGNUGeneralPublicLicense,+*version2,aspublishedbytheFreeSoftwareFoundation.+*+*Thisprogramisdistributedinthehopeitwillbeuseful,butWITHOUT+*ANYWARRANTY;withouteventheimpliedwarrantyofMERCHANTABILITYor+*FITNESSFORAPARTICULARPURPOSE.SeetheGNUGeneralPublicLicensefor+*moredetails.+*/++#include<linux/mutex.h>+#include<soc/rockchip/rockchip_dmc.h>++staticintnum_wait;+staticintnum_disable;+staticBLOCKING_NOTIFIER_HEAD(dmc_notifier_list);+staticDEFINE_MUTEX(dmc_en_lock);+staticDEFINE_MUTEX(dmc_sync_lock);++/**+*rockchip_dmc_enabled-Returnstrueifdmcfreqisenabled,falseotherwise.+*/+boolrockchip_dmc_enabled(void)+{+returnnum_disable<=0&&num_wait<=1;+}++/**+*rockchip_dmc_enable-Enabledmcfrequencyscaling.Willonlyenable+*frequencyscalingifthereare1orfewernotifiers.Calltoundo+*rockchip_dmc_disable.+*/+voidrockchip_dmc_enable(void)+{+mutex_lock(&dmc_en_lock);+num_disable--;+WARN_ON(num_disable<0);+if(rockchip_dmc_enabled())+dmc_event(DMC_ENABLE);+mutex_unlock(&dmc_en_lock);+}++/**+*rockchip_dmc_disable-Disabledmcfrequencyscaling.Callwhensomething+*cannotcoincidewithdmcfrequencyscaling.+*/+voidrockchip_dmc_disable(void)+{+mutex_lock(&dmc_en_lock);+if(rockchip_dmc_enabled())+dmc_event(DMC_DISABLE);+num_disable++;+mutex_unlock(&dmc_en_lock);+}++voiddmc_event(intevent)+{+mutex_lock(&dmc_sync_lock);+blocking_notifier_call_chain(&dmc_notifier_list,event,NULL);+mutex_unlock(&dmc_sync_lock);+}++/**+*dmc_register_notifier-registeradrivertodmcchain+*@nb:notifierfunctiontoregister+*/+intdmc_register_notifier(structnotifier_block*nb)+{+intret;++if(!nb)+return-EINVAL;++ret=blocking_notifier_chain_register(&dmc_notifier_list,nb);++returnret;+}++/**+*dmc_unregister_notifier-unregisteradriverfromdmcchain+*@nb:removenotifierfunction+*/+intdmc_unregister_notifier(structnotifier_block*nb)+{+intret;++if(!nb)+return-EINVAL;++ret=blocking_notifier_chain_unregister(&dmc_notifier_list,nb);++returnret;+}++/**+*rockchip_dmc_get-Registerthenotifierblockforthedmcchain.+*@nbThedmcnotifierblocktoregister+*/+introckchip_dmc_get(structnotifier_block*nb)+{+if(!nb)+return-EINVAL;++mutex_lock(&dmc_en_lock);++/*+*ifhavetwonotifier(enabletwovopetc),+*needtodisabledmc+*/+if(num_wait==1&&num_disable<=0)+dmc_event(DMC_DISABLE);+num_wait++;+dmc_register_notifier(nb);+mutex_unlock(&dmc_en_lock);++return0;+}++/**+*rockchip_dmc_put-Removethenotifierblockfromthedmcchain.+*@nbThedmcnotifierblocktounregister+*/+introckchip_dmc_put(structnotifier_block*nb)+{+if(!nb)+return-EINVAL;++mutex_lock(&dmc_en_lock);+num_wait--;++/* if notifier from 2 back to 1, enable dmc again */+if(num_wait==1&&num_disable<=0)+dmc_event(DMC_ENABLE);+dmc_unregister_notifier(nb);+mutex_unlock(&dmc_en_lock);++return0;+}
Hi Lin,
I add the some comment on below. If you modify it,
You can add my acked-by tag. Looks good to me.
Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
Also, I'd like you to add me to mail thread
on next version because I'm supporter of devfreq-event.
On 2016? 06? 03? 18:55, Lin Huang wrote:
quoted hunk
on rk3399 platform, there is dfi conroller can monitor
ddr load, base on this result, we can do ddr freqency
scaling.
Signed-off-by: Lin Huang <redacted>
---
Changes in v1:
- NOne
drivers/devfreq/event/Kconfig | 7 +
drivers/devfreq/event/Makefile | 1 +
drivers/devfreq/event/rockchip-dfi.c | 265 +++++++++++++++++++++++++++++++++++
3 files changed, 273 insertions(+)
create mode 100644 drivers/devfreq/event/rockchip-dfi.c
You can simply return the PTR_ERR(data->edev) without 'ret' variable as following:
return PTR_ERR(data->edev);
+ }
+
+ ret = clk_prepare_enable(data->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable clk: %d\n", ret);
+ clk_disable_unprepare(data->clk);
+ return ret;
+ }
The following two functions handle the clock. So, rockchip_dfi_probe()
don't need to enable the clock. Just pass the role of clock control to the following functions.
Because of calling the twice of enable function of clock, the usage count of clock
is mismatch when disabling the clock.
- rockchip_dfi_enable(struct devfreq_event_dev *edev) enable the clock.
- rockchip_dfi_disable(struct devfreq_event_dev *edev) disable the clock.
From: Shawn Lin <shawn.lin@rock-chips.com> Date: 2016-06-03 12:30:09
Hi Lin,
It looks good with only a few minor comments.
On 2016/6/3 17:55, Lin Huang wrote:
quoted hunk
On new rockchip platform(rk3399 etc), there have dcf controller to
do ddr frequency scaling, and this controller will implement in
arm-trust-firmware. We add a special clock-type to handle that.
Signed-off-by: Lin Huang <redacted>
---
Changes in v1:
- None
drivers/clk/rockchip/Makefile | 1 +
drivers/clk/rockchip/clk-ddr.c | 147 +++++++++++++++++++++++++++++++++++++++++
drivers/clk/rockchip/clk.c | 9 +++
drivers/clk/rockchip/clk.h | 27 ++++++++
4 files changed, 184 insertions(+)
create mode 100644 drivers/clk/rockchip/clk-ddr.c
Hi Shawn,
Am Freitag, 3. Juni 2016, 20:34:52 schrieb Shawn Lin:
How about merge it into your patch#3.
see comments from Doug and me on previous version.
clock-ids should always be separate patches, as we will need them in both
clock and devicetree branches, so they must be in a separate branch shared
between clock and dts branches.
Heiko
On 2016/6/3 17:55, Lin Huang wrote:
quoted
Signed-off-by: Lin Huang <redacted>
---
Changes in v1:
- None
include/dt-bindings/clock/rk3399-cru.h | 1 +
1 file changed, 1 insertion(+)
From: Shawn Lin <shawn.lin@rock-chips.com> Date: 2016-06-03 12:48:19
? 2016/6/3 20:36, Heiko St?bner ??:
Hi Shawn,
Am Freitag, 3. Juni 2016, 20:34:52 schrieb Shawn Lin:
quoted
How about merge it into your patch#3.
see comments from Doug and me on previous version.
clock-ids should always be separate patches, as we will need them in both
clock and devicetree branches, so they must be in a separate branch shared
between clock and dts branches.
Ah, I missed the previous version as I think it should be from
non-version to v2 rather than from non-version to v1, which IIRC is from
Doug. :)
Anyway, thanks for explaining this.
Heiko
quoted
On 2016/6/3 17:55, Lin Huang wrote:
quoted
Signed-off-by: Lin Huang <redacted>
---
Changes in v1:
- None
include/dt-bindings/clock/rk3399-cru.h | 1 +
1 file changed, 1 insertion(+)
Am Freitag, 3. Juni 2016, 17:55:14 schrieb Lin Huang:
quoted hunk
On new rockchip platform(rk3399 etc), there have dcf controller to
do ddr frequency scaling, and this controller will implement in
arm-trust-firmware. We add a special clock-type to handle that.
Signed-off-by: Lin Huang <redacted>
---
Changes in v1:
- None
drivers/clk/rockchip/Makefile | 1 +
drivers/clk/rockchip/clk-ddr.c | 147
+++++++++++++++++++++++++++++++++++++++++ drivers/clk/rockchip/clk.c |
9 +++
drivers/clk/rockchip/clk.h | 27 ++++++++
4 files changed, 184 insertions(+)
create mode 100644 drivers/clk/rockchip/clk-ddr.c
+
+static int rockchip_ddrclk_set_rate(struct clk_hw *hw, unsigned long drate,
+ unsigned long prate)
+{
+ struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw);
+ unsigned long flags;
+
+ spin_lock_irqsave(ddrclk->lock, flags);
+
+ /* TODO: set ddr rate in bl31 */
I expect this interface to be in existence and merged into the main ATF first.
Right now the whole clock-type does nothing more than a simple COMPOSITE with
added CLK_DIVIDER_READ_ONLY | CLK_MUX_READ_ONLY.
Also Mike is propably still working in the so called coordinated rate change
for clocks needing special handling on rate changes, which might provide a
second approach to this.
So please, first of all get the ATF-interface merged and meanwhile if you need
to read the clock-rate, just use a regular composite, with the read-only flags.
+ spin_unlock_irqrestore(ddrclk->lock, flags);
+
+ return 0;
+}
+
+static unsigned long
+rockchip_ddrclk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw);
+ int val;
+
+ val = clk_readl(ddrclk->reg_base +
+ ddrclk->mux_offset) >> ddrclk->div_shift;
+ val &= val_mask(ddrclk->div_width);
+
+ return DIV_ROUND_UP_ULL((u64)parent_rate, val + 1);
Am Freitag, 3. Juni 2016, 17:55:16 schrieb Lin Huang:
quoted hunk
add ddrc clock setting, so we can do ddr frequency
scaling on rk3399 platform in future.
Signed-off-by: Lin Huang <redacted>
---
Changes in v1:
- remove ddrc source CLK_IGNORE_UNUSED flag, Suggestion by Doug
- move clk_ddrc and clk_ddrc_dpll_src to critical, Suggestion by Doug
drivers/clk/rockchip/clk-rk3399.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/drivers/clk/rockchip/clk-rk3399.c
b/drivers/clk/rockchip/clk-rk3399.c index f1d8e44..29afb88 100644
as said in the other patch, just make this a regular COMPOSITE_NOGATE with
CLK_DIVIDER_READ_ONLY | CLK_MUX_READ_ONLY until that interface to the ATF
exists and is approved.
That way you can still read back the clock rate without anything changing the
clock-rate, but we don't need to add duplicate code for it.
Why does your clk_ddrc_dpll_src need a separate critical entry. Any code
changing the clk_ddrc parent should make sure the new parent is enabled. (The
clock-framework of course does this already).
On Fri, Jun 03, 2016 at 05:55:17PM +0800, Lin Huang wrote:
[...]
+ ret = clk_prepare_enable(data->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable clk: %d\n", ret);
+ clk_disable_unprepare(data->clk);
+ return ret;
+ }
This is going to give you a large WARN. clk_prepare_enable() already
leaves the clock in a proper state when it fails (i.e. it calls
clk_unprepare() if the clk_enable() part failed), so calling
clk_disable_unprepare() upon failure is going to unbalance the
reference counts.
Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160603/74ea7cb3/attachment.sig>
Hi Lin,
It looks good with only a few minor comments.
On 2016/6/3 17:55, Lin Huang wrote:
quoted
On new rockchip platform(rk3399 etc), there have dcf controller to
do ddr frequency scaling, and this controller will implement in
arm-trust-firmware. We add a special clock-type to handle that.
Signed-off-by: Lin Huang <redacted>
---
Changes in v1:
- None
drivers/clk/rockchip/Makefile | 1 +
drivers/clk/rockchip/clk-ddr.c | 147
+++++++++++++++++++++++++++++++++++++++++
drivers/clk/rockchip/clk.c | 9 +++
drivers/clk/rockchip/clk.h | 27 ++++++++
4 files changed, 184 insertions(+)
create mode 100644 drivers/clk/rockchip/clk-ddr.c
diff --git a/drivers/clk/rockchip/Makefile
b/drivers/clk/rockchip/Makefile
index f47a2fa..b5f2c8e 100644
Hi Heiko,
On 2016?06?03? 20:51, Heiko St?bner wrote:
Am Freitag, 3. Juni 2016, 17:55:14 schrieb Lin Huang:
quoted
On new rockchip platform(rk3399 etc), there have dcf controller to
do ddr frequency scaling, and this controller will implement in
arm-trust-firmware. We add a special clock-type to handle that.
Signed-off-by: Lin Huang <redacted>
---
Changes in v1:
- None
drivers/clk/rockchip/Makefile | 1 +
drivers/clk/rockchip/clk-ddr.c | 147
+++++++++++++++++++++++++++++++++++++++++ drivers/clk/rockchip/clk.c |
9 +++
drivers/clk/rockchip/clk.h | 27 ++++++++
4 files changed, 184 insertions(+)
create mode 100644 drivers/clk/rockchip/clk-ddr.c
+
+static int rockchip_ddrclk_set_rate(struct clk_hw *hw, unsigned long drate,
+ unsigned long prate)
+{
+ struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw);
+ unsigned long flags;
+
+ spin_lock_irqsave(ddrclk->lock, flags);
+
+ /* TODO: set ddr rate in bl31 */
I expect this interface to be in existence and merged into the main ATF first.
Right now the whole clock-type does nothing more than a simple COMPOSITE with
added CLK_DIVIDER_READ_ONLY | CLK_MUX_READ_ONLY.
Also Mike is propably still working in the so called coordinated rate change
for clocks needing special handling on rate changes, which might provide a
second approach to this.
You mean there is a patch set can handle it now? Can you tell me
the ID,
I want to check it.
So please, first of all get the ATF-interface merged and meanwhile if you need
to read the clock-rate, just use a regular composite, with the read-only flags.
My colleague are wroking on ATF code now, I agree with you, We can
not merge
this patch set before ATF-interface merged. And we do not need to
add a new code
if we only want to read ddr clock rate(we can get the ddr rate to
read dpll), so i prefer
to keep this function for now, and do review first, once the ATF
code ready, we can merge
soon it(i hope :-P ) .
quoted
+ spin_unlock_irqrestore(ddrclk->lock, flags);
+
+ return 0;
+}
+
+static unsigned long
+rockchip_ddrclk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw);
+ int val;
+
+ val = clk_readl(ddrclk->reg_base +
+ ddrclk->mux_offset) >> ddrclk->div_shift;
+ val &= val_mask(ddrclk->div_width);
+
+ return DIV_ROUND_UP_ULL((u64)parent_rate, val + 1);
Hi Heiko,
On 2016?06?03? 20:56, Heiko St?bner wrote:
Am Freitag, 3. Juni 2016, 17:55:16 schrieb Lin Huang:
quoted
add ddrc clock setting, so we can do ddr frequency
scaling on rk3399 platform in future.
Signed-off-by: Lin Huang <redacted>
---
Changes in v1:
- remove ddrc source CLK_IGNORE_UNUSED flag, Suggestion by Doug
- move clk_ddrc and clk_ddrc_dpll_src to critical, Suggestion by Doug
drivers/clk/rockchip/clk-rk3399.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/drivers/clk/rockchip/clk-rk3399.c
b/drivers/clk/rockchip/clk-rk3399.c index f1d8e44..29afb88 100644
as said in the other patch, just make this a regular COMPOSITE_NOGATE with
CLK_DIVIDER_READ_ONLY | CLK_MUX_READ_ONLY until that interface to the ATF
exists and is approved.
That way you can still read back the clock rate without anything changing the
clock-rate, but we don't need to add duplicate code for it.
Why does your clk_ddrc_dpll_src need a separate critical entry. Any code
changing the clk_ddrc parent should make sure the new parent is enabled. (The
clock-framework of course does this already).
Hi Heiko,
On 2016?06?03? 20:51, Heiko St?bner wrote:
Am Freitag, 3. Juni 2016, 17:55:14 schrieb Lin Huang:
quoted
On new rockchip platform(rk3399 etc), there have dcf controller to
do ddr frequency scaling, and this controller will implement in
arm-trust-firmware. We add a special clock-type to handle that.
Signed-off-by: Lin Huang <redacted>
---
Changes in v1:
- None
drivers/clk/rockchip/Makefile | 1 +
drivers/clk/rockchip/clk-ddr.c | 147
+++++++++++++++++++++++++++++++++++++++++ drivers/clk/rockchip/clk.c |
9 +++
drivers/clk/rockchip/clk.h | 27 ++++++++
4 files changed, 184 insertions(+)
create mode 100644 drivers/clk/rockchip/clk-ddr.c
+
+static int rockchip_ddrclk_set_rate(struct clk_hw *hw, unsigned long drate,
+ unsigned long prate)
+{
+ struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw);
+ unsigned long flags;
+
+ spin_lock_irqsave(ddrclk->lock, flags);
+
+ /* TODO: set ddr rate in bl31 */
I expect this interface to be in existence and merged into the main ATF first.
Right now the whole clock-type does nothing more than a simple COMPOSITE with
added CLK_DIVIDER_READ_ONLY | CLK_MUX_READ_ONLY.
Also Mike is propably still working in the so called coordinated rate change
for clocks needing special handling on rate changes, which might provide a
second approach to this.
You mean there is a patch set can handle it now? Can you tell me
the ID,
I want to check it.
So please, first of all get the ATF-interface merged and meanwhile if you need
to read the clock-rate, just use a regular composite, with the read-only flags.
My colleague are wroking on ATF code now, I agree with you, We can
not merge
this patch set before ATF-interface merged. And we do not need to
add a new code
if we only want to read ddr clock rate(we can get the ddr rate to
read dpll), so i prefer
to keep this function for now, and do review first, once the ATF
code ready, we can merge
soon(i hope :-P ) .
quoted
+ spin_unlock_irqrestore(ddrclk->lock, flags);
+
+ return 0;
+}
+
+static unsigned long
+rockchip_ddrclk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw);
+ int val;
+
+ val = clk_readl(ddrclk->reg_base +
+ ddrclk->mux_offset) >> ddrclk->div_shift;
+ val &= val_mask(ddrclk->div_width);
+
+ return DIV_ROUND_UP_ULL((u64)parent_rate, val + 1);
Hi Lin,
I add the some comment on below. If you modify it,
You can add my acked-by tag. Looks good to me.
Thanks for you reviewing, i will update the code folloiwing your comment.
Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
Also, I'd like you to add me to mail thread
on next version because I'm supporter of devfreq-event.
I am sorry for missing you mail in before patch:-[ , will add you to
mail thread next vesion.
On 2016? 06? 03? 18:55, Lin Huang wrote:
quoted
on rk3399 platform, there is dfi conroller can monitor
ddr load, base on this result, we can do ddr freqency
scaling.
Signed-off-by: Lin Huang <redacted>
---
Changes in v1:
- NOne
drivers/devfreq/event/Kconfig | 7 +
drivers/devfreq/event/Makefile | 1 +
drivers/devfreq/event/rockchip-dfi.c | 265 +++++++++++++++++++++++++++++++++++
3 files changed, 273 insertions(+)
create mode 100644 drivers/devfreq/event/rockchip-dfi.c
You can simply return the PTR_ERR(data->edev) without 'ret' variable as following:
return PTR_ERR(data->edev);
quoted
+ }
+
+ ret = clk_prepare_enable(data->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable clk: %d\n", ret);
+ clk_disable_unprepare(data->clk);
+ return ret;
+ }
The following two functions handle the clock. So, rockchip_dfi_probe()
don't need to enable the clock. Just pass the role of clock control to the following functions.
Because of calling the twice of enable function of clock, the usage count of clock
is mismatch when disabling the clock.
- rockchip_dfi_enable(struct devfreq_event_dev *edev) enable the clock.
- rockchip_dfi_disable(struct devfreq_event_dev *edev) disable the clock.
Hi Thierry,
On 2016?06?04? 00:54, Thierry Reding wrote:
On Fri, Jun 03, 2016 at 05:55:17PM +0800, Lin Huang wrote:
[...]
quoted
+ ret = clk_prepare_enable(data->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable clk: %d\n", ret);
+ clk_disable_unprepare(data->clk);
+ return ret;
+ }
This is going to give you a large WARN. clk_prepare_enable() already
leaves the clock in a proper state when it fails (i.e. it calls
clk_unprepare() if the clk_enable() part failed), so calling
clk_disable_unprepare() upon failure is going to unbalance the
reference counts.