Path: blob/main/sys/contrib/ncsw/Peripherals/FM/Rtc/fman_rtc.c
48417 views
/*1* Copyright 2008-2013 Freescale Semiconductor Inc.2*3* Redistribution and use in source and binary forms, with or without4* modification, are permitted provided that the following conditions are met:5* * Redistributions of source code must retain the above copyright6* notice, this list of conditions and the following disclaimer.7* * Redistributions in binary form must reproduce the above copyright8* notice, this list of conditions and the following disclaimer in the9* documentation and/or other materials provided with the distribution.10* * Neither the name of Freescale Semiconductor nor the11* names of its contributors may be used to endorse or promote products12* derived from this software without specific prior written permission.13*14*15* ALTERNATIVELY, this software may be distributed under the terms of the16* GNU General Public License ("GPL") as published by the Free Software17* Foundation, either version 2 of that License or (at your option) any18* later version.19*20* THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY21* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED22* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE23* DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY24* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES25* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;26* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND27* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT28* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS29* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.30*/3132#include "fsl_fman_rtc.h"3334void fman_rtc_defconfig(struct rtc_cfg *cfg)35{36int i;37cfg->src_clk = DEFAULT_SRC_CLOCK;38cfg->invert_input_clk_phase = DEFAULT_INVERT_INPUT_CLK_PHASE;39cfg->invert_output_clk_phase = DEFAULT_INVERT_OUTPUT_CLK_PHASE;40cfg->pulse_realign = DEFAULT_PULSE_REALIGN;41for (i = 0; i < FMAN_RTC_MAX_NUM_OF_ALARMS; i++)42cfg->alarm_polarity[i] = DEFAULT_ALARM_POLARITY;43for (i = 0; i < FMAN_RTC_MAX_NUM_OF_EXT_TRIGGERS; i++)44cfg->trigger_polarity[i] = DEFAULT_TRIGGER_POLARITY;45}4647uint32_t fman_rtc_get_events(struct rtc_regs *regs)48{49return ioread32be(®s->tmr_tevent);50}5152uint32_t fman_rtc_get_event(struct rtc_regs *regs, uint32_t ev_mask)53{54return ioread32be(®s->tmr_tevent) & ev_mask;55}5657uint32_t fman_rtc_get_interrupt_mask(struct rtc_regs *regs)58{59return ioread32be(®s->tmr_temask);60}6162void fman_rtc_set_interrupt_mask(struct rtc_regs *regs, uint32_t mask)63{64iowrite32be(mask, ®s->tmr_temask);65}6667void fman_rtc_ack_event(struct rtc_regs *regs, uint32_t events)68{69iowrite32be(events, ®s->tmr_tevent);70}7172uint32_t fman_rtc_check_and_clear_event(struct rtc_regs *regs)73{74uint32_t event;7576event = ioread32be(®s->tmr_tevent);77event &= ioread32be(®s->tmr_temask);7879if (event)80iowrite32be(event, ®s->tmr_tevent);81return event;82}8384uint32_t fman_rtc_get_frequency_compensation(struct rtc_regs *regs)85{86return ioread32be(®s->tmr_add);87}8889void fman_rtc_set_frequency_compensation(struct rtc_regs *regs, uint32_t val)90{91iowrite32be(val, ®s->tmr_add);92}9394void fman_rtc_enable_interupt(struct rtc_regs *regs, uint32_t events)95{96fman_rtc_set_interrupt_mask(regs, fman_rtc_get_interrupt_mask(regs) | events);97}9899void fman_rtc_disable_interupt(struct rtc_regs *regs, uint32_t events)100{101fman_rtc_set_interrupt_mask(regs, fman_rtc_get_interrupt_mask(regs) & ~events);102}103104void fman_rtc_set_timer_alarm_l(struct rtc_regs *regs, int index, uint32_t val)105{106iowrite32be(val, ®s->tmr_alarm[index].tmr_alarm_l);107}108109void fman_rtc_set_timer_fiper(struct rtc_regs *regs, int index, uint32_t val)110{111iowrite32be(val, ®s->tmr_fiper[index]);112}113114void fman_rtc_set_timer_alarm(struct rtc_regs *regs, int index, int64_t val)115{116iowrite32be((uint32_t)val, ®s->tmr_alarm[index].tmr_alarm_l);117iowrite32be((uint32_t)(val >> 32), ®s->tmr_alarm[index].tmr_alarm_h);118}119120void fman_rtc_set_timer_offset(struct rtc_regs *regs, int64_t val)121{122iowrite32be((uint32_t)val, ®s->tmr_off_l);123iowrite32be((uint32_t)(val >> 32), ®s->tmr_off_h);124}125126uint64_t fman_rtc_get_trigger_stamp(struct rtc_regs *regs, int id)127{128uint64_t time;129/* TMR_CNT_L must be read first to get an accurate value */130time = (uint64_t)ioread32be(®s->tmr_etts[id].tmr_etts_l);131time |= ((uint64_t)ioread32be(®s->tmr_etts[id].tmr_etts_h)132<< 32);133134return time;135}136137uint32_t fman_rtc_get_timer_ctrl(struct rtc_regs *regs)138{139return ioread32be(®s->tmr_ctrl);140}141142void fman_rtc_set_timer_ctrl(struct rtc_regs *regs, uint32_t val)143{144iowrite32be(val, ®s->tmr_ctrl);145}146147void fman_rtc_timers_soft_reset(struct rtc_regs *regs)148{149fman_rtc_set_timer_ctrl(regs, FMAN_RTC_TMR_CTRL_TMSR);150DELAY(10);151fman_rtc_set_timer_ctrl(regs, 0);152}153154void fman_rtc_init(struct rtc_cfg *cfg, struct rtc_regs *regs, int num_alarms,155int num_fipers, int num_ext_triggers, bool init_freq_comp,156uint32_t freq_compensation, uint32_t output_clock_divisor)157{158uint32_t tmr_ctrl;159int i;160161fman_rtc_timers_soft_reset(regs);162163/* Set the source clock */164switch (cfg->src_clk) {165case E_FMAN_RTC_SOURCE_CLOCK_SYSTEM:166tmr_ctrl = FMAN_RTC_TMR_CTRL_CKSEL_MAC_CLK;167break;168case E_FMAN_RTC_SOURCE_CLOCK_OSCILATOR:169tmr_ctrl = FMAN_RTC_TMR_CTRL_CKSEL_OSC_CLK;170break;171default:172/* Use a clock from the External TMR reference clock.*/173tmr_ctrl = FMAN_RTC_TMR_CTRL_CKSEL_EXT_CLK;174break;175}176177/* whatever period the user picked, the timestamp will advance in '1'178* every time the period passed. */179tmr_ctrl |= ((1 << FMAN_RTC_TMR_CTRL_TCLK_PERIOD_SHIFT) &180FMAN_RTC_TMR_CTRL_TCLK_PERIOD_MASK);181182if (cfg->invert_input_clk_phase)183tmr_ctrl |= FMAN_RTC_TMR_CTRL_CIPH;184if (cfg->invert_output_clk_phase)185tmr_ctrl |= FMAN_RTC_TMR_CTRL_COPH;186187for (i = 0; i < num_alarms; i++) {188if (cfg->alarm_polarity[i] ==189E_FMAN_RTC_ALARM_POLARITY_ACTIVE_LOW)190tmr_ctrl |= (FMAN_RTC_TMR_CTRL_ALMP1 >> i);191}192193for (i = 0; i < num_ext_triggers; i++)194if (cfg->trigger_polarity[i] ==195E_FMAN_RTC_TRIGGER_ON_FALLING_EDGE)196tmr_ctrl |= (FMAN_RTC_TMR_CTRL_ETEP1 << i);197198if (!cfg->timer_slave_mode && cfg->bypass)199tmr_ctrl |= FMAN_RTC_TMR_CTRL_BYP;200201fman_rtc_set_timer_ctrl(regs, tmr_ctrl);202if (init_freq_comp)203fman_rtc_set_frequency_compensation(regs, freq_compensation);204205/* Clear TMR_ALARM registers */206for (i = 0; i < num_alarms; i++)207fman_rtc_set_timer_alarm(regs, i, 0xFFFFFFFFFFFFFFFFLL);208209/* Clear TMR_TEVENT */210fman_rtc_ack_event(regs, FMAN_RTC_TMR_TEVENT_ALL);211212/* Initialize TMR_TEMASK */213fman_rtc_set_interrupt_mask(regs, 0);214215/* Clear TMR_FIPER registers */216for (i = 0; i < num_fipers; i++)217fman_rtc_set_timer_fiper(regs, i, 0xFFFFFFFF);218219/* Initialize TMR_PRSC */220iowrite32be(output_clock_divisor, ®s->tmr_prsc);221222/* Clear TMR_OFF */223fman_rtc_set_timer_offset(regs, 0);224}225226bool fman_rtc_is_enabled(struct rtc_regs *regs)227{228return (bool)(fman_rtc_get_timer_ctrl(regs) & FMAN_RTC_TMR_CTRL_TE);229}230231void fman_rtc_enable(struct rtc_regs *regs, bool reset_clock)232{233uint32_t tmr_ctrl = fman_rtc_get_timer_ctrl(regs);234235/* TODO check that no timestamping MACs are working in this stage. */236if (reset_clock) {237fman_rtc_set_timer_ctrl(regs, (tmr_ctrl | FMAN_RTC_TMR_CTRL_TMSR));238239DELAY(10);240/* Clear TMR_OFF */241fman_rtc_set_timer_offset(regs, 0);242}243244fman_rtc_set_timer_ctrl(regs, (tmr_ctrl | FMAN_RTC_TMR_CTRL_TE));245}246247void fman_rtc_disable(struct rtc_regs *regs)248{249fman_rtc_set_timer_ctrl(regs, (fman_rtc_get_timer_ctrl(regs)250& ~(FMAN_RTC_TMR_CTRL_TE)));251}252253void fman_rtc_clear_periodic_pulse(struct rtc_regs *regs, int id)254{255uint32_t tmp_reg;256if (id == 0)257tmp_reg = FMAN_RTC_TMR_TEVENT_PP1;258else259tmp_reg = FMAN_RTC_TMR_TEVENT_PP2;260fman_rtc_disable_interupt(regs, tmp_reg);261262tmp_reg = fman_rtc_get_timer_ctrl(regs);263if (tmp_reg & FMAN_RTC_TMR_CTRL_FS)264fman_rtc_set_timer_ctrl(regs, tmp_reg & ~FMAN_RTC_TMR_CTRL_FS);265266fman_rtc_set_timer_fiper(regs, id, 0xFFFFFFFF);267}268269void fman_rtc_clear_external_trigger(struct rtc_regs *regs, int id)270{271uint32_t tmpReg, tmp_ctrl;272273if (id == 0)274tmpReg = FMAN_RTC_TMR_TEVENT_ETS1;275else276tmpReg = FMAN_RTC_TMR_TEVENT_ETS2;277fman_rtc_disable_interupt(regs, tmpReg);278279if (id == 0)280tmpReg = FMAN_RTC_TMR_CTRL_PP1L;281else282tmpReg = FMAN_RTC_TMR_CTRL_PP2L;283tmp_ctrl = fman_rtc_get_timer_ctrl(regs);284if (tmp_ctrl & tmpReg)285fman_rtc_set_timer_ctrl(regs, tmp_ctrl & ~tmpReg);286}287288void fman_rtc_set_alarm(struct rtc_regs *regs, int id, uint32_t val, bool enable)289{290uint32_t tmpReg;291fman_rtc_set_timer_alarm(regs, id, val);292if (enable) {293if (id == 0)294tmpReg = FMAN_RTC_TMR_TEVENT_ALM1;295else296tmpReg = FMAN_RTC_TMR_TEVENT_ALM2;297fman_rtc_enable_interupt(regs, tmpReg);298}299}300301void fman_rtc_set_periodic_pulse(struct rtc_regs *regs, int id, uint32_t val,302bool enable)303{304uint32_t tmpReg;305fman_rtc_set_timer_fiper(regs, id, val);306if (enable) {307if (id == 0)308tmpReg = FMAN_RTC_TMR_TEVENT_PP1;309else310tmpReg = FMAN_RTC_TMR_TEVENT_PP2;311fman_rtc_enable_interupt(regs, tmpReg);312}313}314315void fman_rtc_set_ext_trigger(struct rtc_regs *regs, int id, bool enable,316bool use_pulse_as_input)317{318uint32_t tmpReg;319if (enable) {320if (id == 0)321tmpReg = FMAN_RTC_TMR_TEVENT_ETS1;322else323tmpReg = FMAN_RTC_TMR_TEVENT_ETS2;324fman_rtc_enable_interupt(regs, tmpReg);325}326if (use_pulse_as_input) {327if (id == 0)328tmpReg = FMAN_RTC_TMR_CTRL_PP1L;329else330tmpReg = FMAN_RTC_TMR_CTRL_PP2L;331fman_rtc_set_timer_ctrl(regs, fman_rtc_get_timer_ctrl(regs) | tmpReg);332}333}334335336