Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
adam.huang
Arm Trusted Firmware
Commits
a542faad
Unverified
Commit
a542faad
authored
Aug 30, 2018
by
Soby Mathew
Committed by
GitHub
Aug 30, 2018
Browse files
Merge pull request #1514 from glneo/for-upstream-psci
K3 PSCI Support
parents
2a7c9e15
c8761b4d
Changes
10
Hide whitespace changes
Inline
Side-by-side
plat/ti/k3/board/generic/include/board_def.h
View file @
a542faad
...
...
@@ -32,4 +32,7 @@
#define PLAT_MAX_OFF_STATE U(2)
#define PLAT_MAX_RET_STATE U(1)
#define PLAT_PROC_START_ID 32
#define PLAT_PROC_DEVICE_START_ID 202
#endif
/* BOARD_DEF_H */
plat/ti/k3/common/drivers/sec_proxy/sec_proxy.c
0 → 100644
View file @
a542faad
/*
* Texas Instruments K3 Secure Proxy Driver
* Based on Linux and U-Boot implementation
*
* Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <debug.h>
#include <errno.h>
#include <mmio.h>
#include <platform_def.h>
#include <stdlib.h>
#include <utils.h>
#include <utils_def.h>
#include "sec_proxy.h"
/* SEC PROXY RT THREAD STATUS */
#define RT_THREAD_STATUS (0x0)
#define RT_THREAD_STATUS_ERROR_SHIFT (31)
#define RT_THREAD_STATUS_ERROR_MASK BIT(31)
#define RT_THREAD_STATUS_CUR_CNT_SHIFT (0)
#define RT_THREAD_STATUS_CUR_CNT_MASK GENMASK(7, 0)
/* SEC PROXY SCFG THREAD CTRL */
#define SCFG_THREAD_CTRL (0x1000)
#define SCFG_THREAD_CTRL_DIR_SHIFT (31)
#define SCFG_THREAD_CTRL_DIR_MASK BIT(31)
#define SEC_PROXY_THREAD(base, x) ((base) + (0x1000 * (x)))
#define THREAD_IS_RX (1)
#define THREAD_IS_TX (0)
/**
* struct k3_sec_proxy_desc - Description of secure proxy integration
* @timeout_us: Timeout for communication (in Microseconds)
* @max_msg_size: Message size in bytes
* @data_start_offset: Offset of the First data register of the thread
* @data_end_offset: Offset of the Last data register of the thread
*/
struct
k3_sec_proxy_desc
{
uint32_t
timeout_us
;
uint16_t
max_msg_size
;
uint16_t
data_start_offset
;
uint16_t
data_end_offset
;
};
/**
* struct k3_sec_proxy_thread - Description of a secure proxy Thread
* @id: Thread ID
* @data: Thread Data path region for target
* @scfg: Secure Config Region for Thread
* @rt: RealTime Region for Thread
*/
struct
k3_sec_proxy_thread
{
uint32_t
id
;
uintptr_t
data
;
uintptr_t
scfg
;
uintptr_t
rt
;
};
/**
* struct k3_sec_proxy_mbox - Description of a Secure Proxy Instance
* @desc: Description of the SoC integration
* @chans: Array for valid thread instances
*/
struct
k3_sec_proxy_mbox
{
const
struct
k3_sec_proxy_desc
desc
;
struct
k3_sec_proxy_thread
threads
[];
};
/*
* Thread ID #0: DMSC notify
* Thread ID #1: DMSC request response
* Thread ID #2: DMSC request high priority
* Thread ID #3: DMSC request low priority
* Thread ID #4: DMSC notify response
*/
#define SP_THREAD(_x) \
[_x] = { \
.id = _x, \
.data = SEC_PROXY_THREAD(SEC_PROXY_DATA_BASE, _x), \
.scfg = SEC_PROXY_THREAD(SEC_PROXY_SCFG_BASE, _x), \
.rt = SEC_PROXY_THREAD(SEC_PROXY_RT_BASE, _x), \
}
static
struct
k3_sec_proxy_mbox
spm
=
{
.
desc
=
{
.
timeout_us
=
SEC_PROXY_TIMEOUT_US
,
.
max_msg_size
=
SEC_PROXY_MAX_MESSAGE_SIZE
,
.
data_start_offset
=
0x4
,
.
data_end_offset
=
0x3C
,
},
.
threads
=
{
SP_THREAD
(
SP_NOTIFY
),
SP_THREAD
(
SP_RESPONSE
),
SP_THREAD
(
SP_HIGH_PRIORITY
),
SP_THREAD
(
SP_LOW_PRIORITY
),
SP_THREAD
(
SP_NOTIFY_RESP
),
},
};
/**
* struct sec_msg_hdr - Message header for secure messages and responses
* @checksum: CRC of message for integrity checking
*/
union
sec_msg_hdr
{
struct
{
uint16_t
checksum
;
uint16_t
reserved
;
}
__packed
;
uint32_t
data
;
};
/**
* k3_sec_proxy_verify_thread() - Verify thread status before
* sending/receiving data
* @spt: Pointer to Secure Proxy thread description
* @dir: Direction of the thread
*
* Return: 0 if all goes well, else appropriate error message
*/
static
inline
int
k3_sec_proxy_verify_thread
(
struct
k3_sec_proxy_thread
*
spt
,
uint32_t
dir
)
{
/* Check for any errors already available */
if
(
mmio_read_32
(
spt
->
rt
+
RT_THREAD_STATUS
)
&
RT_THREAD_STATUS_ERROR_MASK
)
{
ERROR
(
"Thread %d is corrupted, cannot send data
\n
"
,
spt
->
id
);
return
-
EINVAL
;
}
/* Make sure thread is configured for right direction */
if
((
mmio_read_32
(
spt
->
scfg
+
SCFG_THREAD_CTRL
)
&
SCFG_THREAD_CTRL_DIR_MASK
)
!=
(
dir
<<
SCFG_THREAD_CTRL_DIR_SHIFT
))
{
if
(
dir
)
ERROR
(
"Trying to receive data on tx Thread %d
\n
"
,
spt
->
id
);
else
ERROR
(
"Trying to send data on rx Thread %d
\n
"
,
spt
->
id
);
return
-
EINVAL
;
}
/* Check the message queue before sending/receiving data */
uint32_t
tick_start
=
(
uint32_t
)
read_cntpct_el0
();
uint32_t
ticks_per_us
=
SYS_COUNTER_FREQ_IN_TICKS
/
1000000
;
while
(
!
(
mmio_read_32
(
spt
->
rt
+
RT_THREAD_STATUS
)
&
RT_THREAD_STATUS_CUR_CNT_MASK
))
{
VERBOSE
(
"Waiting for thread %d to clear
\n
"
,
spt
->
id
);
if
(((
uint32_t
)
read_cntpct_el0
()
-
tick_start
)
>
(
spm
.
desc
.
timeout_us
*
ticks_per_us
))
{
ERROR
(
"Timeout waiting for thread %d to clear
\n
"
,
spt
->
id
);
return
-
ETIMEDOUT
;
}
}
return
0
;
}
/**
* k3_sec_proxy_send() - Send data over a Secure Proxy thread
* @id: Channel Identifier
* @msg: Pointer to k3_sec_proxy_msg
*
* Return: 0 if all goes well, else appropriate error message
*/
int
k3_sec_proxy_send
(
enum
k3_sec_proxy_chan_id
id
,
const
struct
k3_sec_proxy_msg
*
msg
)
{
struct
k3_sec_proxy_thread
*
spt
=
&
spm
.
threads
[
id
];
union
sec_msg_hdr
secure_header
;
int
num_words
,
trail_bytes
,
i
,
ret
;
uintptr_t
data_reg
;
ret
=
k3_sec_proxy_verify_thread
(
spt
,
THREAD_IS_TX
);
if
(
ret
)
{
ERROR
(
"Thread %d verification failed (%d)
\n
"
,
spt
->
id
,
ret
);
return
ret
;
}
/* Check the message size */
if
(
msg
->
len
+
sizeof
(
secure_header
)
>
spm
.
desc
.
max_msg_size
)
{
ERROR
(
"Thread %d message length %lu > max msg size
\n
"
,
spt
->
id
,
msg
->
len
);
return
-
EINVAL
;
}
/* TODO: Calculate checksum */
secure_header
.
checksum
=
0
;
/* Send the secure header */
data_reg
=
spm
.
desc
.
data_start_offset
;
mmio_write_32
(
spt
->
data
+
data_reg
,
secure_header
.
data
);
data_reg
+=
sizeof
(
uint32_t
);
/* Send whole words */
num_words
=
msg
->
len
/
sizeof
(
uint32_t
);
for
(
i
=
0
;
i
<
num_words
;
i
++
)
{
mmio_write_32
(
spt
->
data
+
data_reg
,
((
uint32_t
*
)
msg
->
buf
)[
i
]);
data_reg
+=
sizeof
(
uint32_t
);
}
/* Send remaining bytes */
trail_bytes
=
msg
->
len
%
sizeof
(
uint32_t
);
if
(
trail_bytes
)
{
uint32_t
data_trail
=
0
;
i
=
msg
->
len
-
trail_bytes
;
while
(
trail_bytes
--
)
{
data_trail
<<=
8
;
data_trail
|=
msg
->
buf
[
i
++
];
}
mmio_write_32
(
spt
->
data
+
data_reg
,
data_trail
);
data_reg
+=
sizeof
(
uint32_t
);
}
/*
* 'data_reg' indicates next register to write. If we did not already
* write on tx complete reg(last reg), we must do so for transmit
*/
if
(
data_reg
<=
spm
.
desc
.
data_end_offset
)
mmio_write_32
(
spt
->
data
+
spm
.
desc
.
data_end_offset
,
0
);
VERBOSE
(
"Message successfully sent on thread %ud
\n
"
,
id
);
return
0
;
}
/**
* k3_sec_proxy_recv() - Receive data from a Secure Proxy thread
* @id: Channel Identifier
* @msg: Pointer to k3_sec_proxy_msg
*
* Return: 0 if all goes well, else appropriate error message
*/
int
k3_sec_proxy_recv
(
uint32_t
id
,
struct
k3_sec_proxy_msg
*
msg
)
{
struct
k3_sec_proxy_thread
*
spt
=
&
spm
.
threads
[
id
];
union
sec_msg_hdr
secure_header
;
uintptr_t
data_reg
;
int
num_words
,
trail_bytes
,
i
,
ret
;
ret
=
k3_sec_proxy_verify_thread
(
spt
,
THREAD_IS_RX
);
if
(
ret
)
{
ERROR
(
"Thread %d verification failed (%d)
\n
"
,
spt
->
id
,
ret
);
return
ret
;
}
/* Read secure header */
data_reg
=
spm
.
desc
.
data_start_offset
;
secure_header
.
data
=
mmio_read_32
(
spt
->
data
+
data_reg
);
data_reg
+=
sizeof
(
uint32_t
);
/* Read whole words */
num_words
=
msg
->
len
/
sizeof
(
uint32_t
);
for
(
i
=
0
;
i
<
num_words
;
i
++
)
{
((
uint32_t
*
)
msg
->
buf
)[
i
]
=
mmio_read_32
(
spt
->
data
+
data_reg
);
data_reg
+=
sizeof
(
uint32_t
);
}
/* Read remaining bytes */
trail_bytes
=
msg
->
len
%
sizeof
(
uint32_t
);
if
(
trail_bytes
)
{
uint32_t
data_trail
=
mmio_read_32
(
spt
->
data
+
data_reg
);
data_reg
+=
sizeof
(
uint32_t
);
i
=
msg
->
len
-
trail_bytes
;
while
(
trail_bytes
--
)
{
msg
->
buf
[
i
]
=
data_trail
&
0xff
;
data_trail
>>=
8
;
}
}
/*
* 'data_reg' indicates next register to read. If we did not already
* read on rx complete reg(last reg), we must do so for receive
*/
if
(
data_reg
<=
spm
.
desc
.
data_end_offset
)
mmio_read_32
(
spt
->
data
+
spm
.
desc
.
data_end_offset
);
/* TODO: Verify checksum */
(
void
)
secure_header
.
checksum
;
VERBOSE
(
"Message successfully received from thread %ud
\n
"
,
id
);
return
0
;
}
plat/ti/k3/common/drivers/sec_proxy/sec_proxy.h
0 → 100644
View file @
a542faad
/*
* Texas Instruments K3 Secure Proxy Driver
* Based on Linux and U-Boot implementation
*
* Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef K3_SEC_PROXY_H
#define K3_SEC_PROXY_H
#include <stdint.h>
/**
* enum k3_sec_proxy_chan_id - Secure Proxy thread IDs
*
* These the available IDs used in k3_sec_proxy_{send,recv}()
*/
enum
k3_sec_proxy_chan_id
{
SP_NOTIFY
=
0
,
SP_RESPONSE
,
SP_HIGH_PRIORITY
,
SP_LOW_PRIORITY
,
SP_NOTIFY_RESP
,
};
/**
* struct k3_sec_proxy_msg - Secure proxy message structure
* @len: Length of data in the Buffer
* @buf: Buffer pointer
*
* This is the structure for data used in k3_sec_proxy_{send,recv}()
*/
struct
k3_sec_proxy_msg
{
size_t
len
;
uint8_t
*
buf
;
};
/**
* k3_sec_proxy_send() - Send data over a Secure Proxy thread
* @id: Channel Identifier
* @msg: Pointer to k3_sec_proxy_msg
*
* Return: 0 if all goes well, else appropriate error message
*/
int
k3_sec_proxy_send
(
enum
k3_sec_proxy_chan_id
id
,
const
struct
k3_sec_proxy_msg
*
msg
);
/**
* k3_sec_proxy_recv() - Receive data from a Secure Proxy thread
* @id: Channel Identifier
* @msg: Pointer to k3_sec_proxy_msg
*
* Return: 0 if all goes well, else appropriate error message
*/
int
k3_sec_proxy_recv
(
enum
k3_sec_proxy_chan_id
id
,
struct
k3_sec_proxy_msg
*
msg
);
#endif
/* K3_SEC_PROXY_H */
plat/ti/k3/common/drivers/ti_sci/ti_sci.c
0 → 100644
View file @
a542faad
/*
* Texas Instruments System Control Interface Driver
* Based on Linux and U-Boot implementation
*
* Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <debug.h>
#include <errno.h>
#include <platform_def.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <sec_proxy.h>
#include "ti_sci_protocol.h"
#include "ti_sci.h"
/**
* struct ti_sci_desc - Description of SoC integration
* @host_id: Host identifier representing the compute entity
* @max_msg_size: Maximum size of data per message that can be handled
*/
struct
ti_sci_desc
{
uint8_t
host_id
;
int
max_msg_size
;
};
/**
* struct ti_sci_info - Structure representing a TI SCI instance
* @desc: SoC description for this instance
* @seq: Seq id used for verification for tx and rx message
*/
struct
ti_sci_info
{
const
struct
ti_sci_desc
desc
;
uint8_t
seq
;
};
static
struct
ti_sci_info
info
=
{
.
desc
=
{
.
host_id
=
TI_SCI_HOST_ID
,
.
max_msg_size
=
TI_SCI_MAX_MESSAGE_SIZE
,
},
.
seq
=
0x0a
,
};
/**
* struct ti_sci_xfer - Structure representing a message flow
* @tx_message: Transmit message
* @rx_message: Receive message
*/
struct
ti_sci_xfer
{
struct
k3_sec_proxy_msg
tx_message
;
struct
k3_sec_proxy_msg
rx_message
;
};
/**
* ti_sci_setup_one_xfer() - Setup one message type
*
* @msg_type: Message type
* @msg_flags: Flag to set for the message
* @tx_buf: Buffer to be sent to mailbox channel
* @tx_message_size: transmit message size
* @rx_buf: Buffer to be received from mailbox channel
* @rx_message_size: receive message size
*
* Helper function which is used by various command functions that are
* exposed to clients of this driver for allocating a message traffic event.
*
* Return: 0 if all goes well, else appropriate error message
*/
static
int
ti_sci_setup_one_xfer
(
uint16_t
msg_type
,
uint32_t
msg_flags
,
void
*
tx_buf
,
size_t
tx_message_size
,
void
*
rx_buf
,
size_t
rx_message_size
,
struct
ti_sci_xfer
*
xfer
)
{
struct
ti_sci_msg_hdr
*
hdr
;
/* Ensure we have sane transfer sizes */
if
(
rx_message_size
>
info
.
desc
.
max_msg_size
||
tx_message_size
>
info
.
desc
.
max_msg_size
||
rx_message_size
<
sizeof
(
*
hdr
)
||
tx_message_size
<
sizeof
(
*
hdr
))
return
-
ERANGE
;
info
.
seq
++
;
hdr
=
(
struct
ti_sci_msg_hdr
*
)
tx_buf
;
hdr
->
seq
=
info
.
seq
;
hdr
->
type
=
msg_type
;
hdr
->
host
=
info
.
desc
.
host_id
;
hdr
->
flags
=
msg_flags
;
xfer
->
tx_message
.
buf
=
tx_buf
;
xfer
->
tx_message
.
len
=
tx_message_size
;
xfer
->
rx_message
.
buf
=
rx_buf
;
xfer
->
rx_message
.
len
=
rx_message_size
;
return
0
;
}
/**
* ti_sci_get_response() - Receive response from mailbox channel
*
* @xfer: Transfer to initiate and wait for response
* @chan: Channel to receive the response
*
* Return: 0 if all goes well, else appropriate error message
*/
static
inline
int
ti_sci_get_response
(
struct
ti_sci_xfer
*
xfer
,
enum
k3_sec_proxy_chan_id
chan
)
{
struct
k3_sec_proxy_msg
*
msg
=
&
xfer
->
rx_message
;
struct
ti_sci_msg_hdr
*
hdr
;
int
ret
;
/* Receive the response */
ret
=
k3_sec_proxy_recv
(
chan
,
msg
);
if
(
ret
)
{
ERROR
(
"Message receive failed (%d)
\n
"
,
ret
);
return
ret
;
}
/* msg is updated by Secure Proxy driver */
hdr
=
(
struct
ti_sci_msg_hdr
*
)
msg
->
buf
;
/* Sanity check for message response */
if
(
hdr
->
seq
!=
info
.
seq
)
{
ERROR
(
"Message for %d is not expected
\n
"
,
hdr
->
seq
);
return
-
EINVAL
;
}
if
(
msg
->
len
>
info
.
desc
.
max_msg_size
)
{
ERROR
(
"Unable to handle %lu xfer (max %d)
\n
"
,
msg
->
len
,
info
.
desc
.
max_msg_size
);
return
-
EINVAL
;
}
return
0
;
}
/**
* ti_sci_do_xfer() - Do one transfer
*
* @xfer: Transfer to initiate and wait for response
*
* Return: 0 if all goes well, else appropriate error message
*/
static
inline
int
ti_sci_do_xfer
(
struct
ti_sci_xfer
*
xfer
)
{
struct
k3_sec_proxy_msg
*
msg
=
&
xfer
->
tx_message
;
int
ret
;
/* Send the message */
ret
=
k3_sec_proxy_send
(
SP_HIGH_PRIORITY
,
msg
);
if
(
ret
)
{
ERROR
(
"Message sending failed (%d)
\n
"
,
ret
);
return
ret
;
}
ret
=
ti_sci_get_response
(
xfer
,
SP_RESPONSE
);
if
(
ret
)
{
ERROR
(
"Failed to get response (%d)
\n
"
,
ret
);
return
ret
;
}
return
0
;
}
/**
* ti_sci_get_revision() - Get the revision of the SCI entity
*
* Updates the SCI information in the internal data structure.
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_get_revision
(
struct
ti_sci_msg_resp_version
*
rev_info
)
{
struct
ti_sci_msg_hdr
hdr
;
struct
ti_sci_xfer
xfer
;
int
ret
;
ret
=
ti_sci_setup_one_xfer
(
TI_SCI_MSG_VERSION
,
0x0
,
&
hdr
,
sizeof
(
hdr
),
rev_info
,
sizeof
(
*
rev_info
),
&
xfer
);
if
(
ret
)
{
ERROR
(
"Message alloc failed (%d)
\n
"
,
ret
);
return
ret
;
}
ret
=
ti_sci_do_xfer
(
&
xfer
);
if
(
ret
)
{
ERROR
(
"Transfer send failed (%d)
\n
"
,
ret
);
return
ret
;
}
return
0
;
}
/**
* ti_sci_is_response_ack() - Generic ACK/NACK message check
*
* @r: pointer to response buffer
*
* Return: true if the response was an ACK, else returns false
*/
static
inline
bool
ti_sci_is_response_ack
(
void
*
r
)
{
struct
ti_sci_msg_hdr
*
hdr
=
r
;
return
hdr
->
flags
&
TI_SCI_FLAG_RESP_GENERIC_ACK
?
true
:
false
;
}
/**
* ti_sci_device_set_state() - Set device state
*
* @id: Device identifier
* @flags: flags to setup for the device
* @state: State to move the device to
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_device_set_state
(
uint32_t
id
,
uint32_t
flags
,
uint8_t
state
)
{
struct
ti_sci_msg_req_set_device_state
req
;
struct
ti_sci_msg_hdr
resp
;
struct
ti_sci_xfer
xfer
;
int
ret
;
ret
=
ti_sci_setup_one_xfer
(
TI_SCI_MSG_SET_DEVICE_STATE
,
flags
|
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED
,
&
req
,
sizeof
(
req
),
&
resp
,
sizeof
(
resp
),
&
xfer
);
if
(
ret
)
{
ERROR
(
"Message alloc failed (%d)
\n
"
,
ret
);
return
ret
;
}
req
.
id
=
id
;
req
.
state
=
state
;
ret
=
ti_sci_do_xfer
(
&
xfer
);
if
(
ret
)
{
ERROR
(
"Transfer send failed (%d)
\n
"
,
ret
);
return
ret
;
}
if
(
!
ti_sci_is_response_ack
(
&
resp
))
return
-
ENODEV
;
return
0
;
}
/**
* ti_sci_device_get_state() - Get device state
*
* @id: Device Identifier
* @clcnt: Pointer to Context Loss Count
* @resets: pointer to resets
* @p_state: pointer to p_state
* @c_state: pointer to c_state
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_device_get_state
(
uint32_t
id
,
uint32_t
*
clcnt
,
uint32_t
*
resets
,
uint8_t
*
p_state
,
uint8_t
*
c_state
)
{
struct
ti_sci_msg_req_get_device_state
req
;
struct
ti_sci_msg_resp_get_device_state
resp
;
struct
ti_sci_xfer
xfer
;
int
ret
;
if
(
!
clcnt
&&
!
resets
&&
!
p_state
&&
!
c_state
)
return
-
EINVAL
;
ret
=
ti_sci_setup_one_xfer
(
TI_SCI_MSG_GET_DEVICE_STATE
,
0
,
&
req
,
sizeof
(
req
),
&
resp
,
sizeof
(
resp
),
&
xfer
);
if
(
ret
)
{
ERROR
(
"Message alloc failed (%d)
\n
"
,
ret
);
return
ret
;
}
req
.
id
=
id
;
ret
=
ti_sci_do_xfer
(
&
xfer
);
if
(
ret
)
{
ERROR
(
"Transfer send failed (%d)
\n
"
,
ret
);
return
ret
;
}
if
(
!
ti_sci_is_response_ack
(
&
resp
))
return
-
ENODEV
;
if
(
clcnt
)
*
clcnt
=
resp
.
context_loss_count
;
if
(
resets
)
*
resets
=
resp
.
resets
;
if
(
p_state
)
*
p_state
=
resp
.
programmed_state
;
if
(
c_state
)
*
c_state
=
resp
.
current_state
;
return
0
;
}
/**
* ti_sci_device_get() - Request for device managed by TISCI
*
* @id: Device Identifier
*
* Request for the device - NOTE: the client MUST maintain integrity of
* usage count by balancing get_device with put_device. No refcounting is
* managed by driver for that purpose.
*
* NOTE: The request is for exclusive access for the processor.
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_device_get
(
uint32_t
id
)
{
return
ti_sci_device_set_state
(
id
,
MSG_FLAG_DEVICE_EXCLUSIVE
,
MSG_DEVICE_SW_STATE_ON
);
}
/**
* ti_sci_device_idle() - Idle a device managed by TISCI
*
* @id: Device Identifier
*
* Request for the device - NOTE: the client MUST maintain integrity of
* usage count by balancing get_device with put_device. No refcounting is
* managed by driver for that purpose.
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_device_idle
(
uint32_t
id
)
{
return
ti_sci_device_set_state
(
id
,
MSG_FLAG_DEVICE_EXCLUSIVE
,
MSG_DEVICE_SW_STATE_RETENTION
);
}
/**
* ti_sci_device_put() - Release a device managed by TISCI
*
* @id: Device Identifier
*
* Request for the device - NOTE: the client MUST maintain integrity of
* usage count by balancing get_device with put_device. No refcounting is
* managed by driver for that purpose.
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_device_put
(
uint32_t
id
)
{
return
ti_sci_device_set_state
(
id
,
0
,
MSG_DEVICE_SW_STATE_AUTO_OFF
);
}
/**
* ti_sci_device_is_valid() - Is the device valid
*
* @id: Device Identifier
*
* Return: 0 if all goes well and the device ID is valid, else return
* appropriate error
*/
int
ti_sci_device_is_valid
(
uint32_t
id
)
{
uint8_t
unused
;
/* check the device state which will also tell us if the ID is valid */
return
ti_sci_device_get_state
(
id
,
NULL
,
NULL
,
NULL
,
&
unused
);
}
/**
* ti_sci_device_get_clcnt() - Get context loss counter
*
* @id: Device Identifier
* @count: Pointer to Context Loss counter to populate
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_device_get_clcnt
(
uint32_t
id
,
uint32_t
*
count
)
{
return
ti_sci_device_get_state
(
id
,
count
,
NULL
,
NULL
,
NULL
);
}
/**
* ti_sci_device_is_idle() - Check if the device is requested to be idle
*
* @id: Device Identifier
* @r_state: true if requested to be idle
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_device_is_idle
(
uint32_t
id
,
bool
*
r_state
)
{
int
ret
;
uint8_t
state
;
if
(
!
r_state
)
return
-
EINVAL
;
ret
=
ti_sci_device_get_state
(
id
,
NULL
,
NULL
,
&
state
,
NULL
);
if
(
ret
)
return
ret
;
*
r_state
=
(
state
==
MSG_DEVICE_SW_STATE_RETENTION
);
return
0
;
}
/**
* ti_sci_device_is_stop() - Check if the device is requested to be stopped
*
* @id: Device Identifier
* @r_state: true if requested to be stopped
* @curr_state: true if currently stopped
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_device_is_stop
(
uint32_t
id
,
bool
*
r_state
,
bool
*
curr_state
)
{
int
ret
;
uint8_t
p_state
,
c_state
;
if
(
!
r_state
&&
!
curr_state
)
return
-
EINVAL
;
ret
=
ti_sci_device_get_state
(
id
,
NULL
,
NULL
,
&
p_state
,
&
c_state
);
if
(
ret
)
return
ret
;
if
(
r_state
)
*
r_state
=
(
p_state
==
MSG_DEVICE_SW_STATE_AUTO_OFF
);
if
(
curr_state
)
*
curr_state
=
(
c_state
==
MSG_DEVICE_HW_STATE_OFF
);
return
0
;
}
/**
* ti_sci_device_is_on() - Check if the device is requested to be ON
*
* @id: Device Identifier
* @r_state: true if requested to be ON
* @curr_state: true if currently ON and active
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_device_is_on
(
uint32_t
id
,
bool
*
r_state
,
bool
*
curr_state
)
{
int
ret
;
uint8_t
p_state
,
c_state
;
if
(
!
r_state
&&
!
curr_state
)
return
-
EINVAL
;
ret
=
ti_sci_device_get_state
(
id
,
NULL
,
NULL
,
&
p_state
,
&
c_state
);
if
(
ret
)
return
ret
;
if
(
r_state
)
*
r_state
=
(
p_state
==
MSG_DEVICE_SW_STATE_ON
);
if
(
curr_state
)
*
curr_state
=
(
c_state
==
MSG_DEVICE_HW_STATE_ON
);
return
0
;
}
/**
* ti_sci_device_is_trans() - Check if the device is currently transitioning
*
* @id: Device Identifier
* @curr_state: true if currently transitioning
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_device_is_trans
(
uint32_t
id
,
bool
*
curr_state
)
{
int
ret
;
uint8_t
state
;
if
(
!
curr_state
)
return
-
EINVAL
;
ret
=
ti_sci_device_get_state
(
id
,
NULL
,
NULL
,
NULL
,
&
state
);
if
(
ret
)
return
ret
;
*
curr_state
=
(
state
==
MSG_DEVICE_HW_STATE_TRANS
);
return
0
;
}
/**
* ti_sci_device_set_resets() - Set resets for device managed by TISCI
*
* @id: Device Identifier
* @reset_state: Device specific reset bit field
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_device_set_resets
(
uint32_t
id
,
uint32_t
reset_state
)
{
struct
ti_sci_msg_req_set_device_resets
req
;
struct
ti_sci_msg_hdr
resp
;
struct
ti_sci_xfer
xfer
;
int
ret
;
ret
=
ti_sci_setup_one_xfer
(
TI_SCI_MSG_SET_DEVICE_RESETS
,
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED
,
&
req
,
sizeof
(
req
),
&
resp
,
sizeof
(
resp
),
&
xfer
);
if
(
ret
)
{
ERROR
(
"Message alloc failed (%d)
\n
"
,
ret
);
return
ret
;
}
req
.
id
=
id
;
req
.
resets
=
reset_state
;
ret
=
ti_sci_do_xfer
(
&
xfer
);
if
(
ret
)
{
ERROR
(
"Transfer send failed (%d)
\n
"
,
ret
);
return
ret
;
}
if
(
!
ti_sci_is_response_ack
(
&
resp
))
return
-
ENODEV
;
return
0
;
}
/**
* ti_sci_device_get_resets() - Get reset state for device managed by TISCI
*
* @id: Device Identifier
* @reset_state: Pointer to reset state to populate
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_device_get_resets
(
uint32_t
id
,
uint32_t
*
reset_state
)
{
return
ti_sci_device_get_state
(
id
,
NULL
,
reset_state
,
NULL
,
NULL
);
}
/**
* ti_sci_clock_set_state() - Set clock state helper
*
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request,
* Each device has its own set of clock inputs, This indexes
* which clock input to modify
* @flags: Header flags as needed
* @state: State to request for the clock
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_clock_set_state
(
uint32_t
dev_id
,
uint8_t
clk_id
,
uint32_t
flags
,
uint8_t
state
)
{
struct
ti_sci_msg_req_set_clock_state
req
;
struct
ti_sci_msg_hdr
resp
;
struct
ti_sci_xfer
xfer
;
int
ret
;
ret
=
ti_sci_setup_one_xfer
(
TI_SCI_MSG_SET_CLOCK_STATE
,
flags
|
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED
,
&
req
,
sizeof
(
req
),
&
resp
,
sizeof
(
resp
),
&
xfer
);
if
(
ret
)
{
ERROR
(
"Message alloc failed (%d)
\n
"
,
ret
);
return
ret
;
}
req
.
dev_id
=
dev_id
;
req
.
clk_id
=
clk_id
;
req
.
request_state
=
state
;
ret
=
ti_sci_do_xfer
(
&
xfer
);
if
(
ret
)
{
ERROR
(
"Transfer send failed (%d)
\n
"
,
ret
);
return
ret
;
}
if
(
!
ti_sci_is_response_ack
(
&
resp
))
return
-
ENODEV
;
return
0
;
}
/**
* ti_sci_clock_get_state() - Get clock state helper
*
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
* Each device has its own set of clock inputs. This indexes
* which clock input to modify.
* @programmed_state: State requested for clock to move to
* @current_state: State that the clock is currently in
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_clock_get_state
(
uint32_t
dev_id
,
uint8_t
clk_id
,
uint8_t
*
programmed_state
,
uint8_t
*
current_state
)
{
struct
ti_sci_msg_req_get_clock_state
req
;
struct
ti_sci_msg_resp_get_clock_state
resp
;
struct
ti_sci_xfer
xfer
;
int
ret
;
if
(
!
programmed_state
&&
!
current_state
)
return
-
EINVAL
;
ret
=
ti_sci_setup_one_xfer
(
TI_SCI_MSG_GET_CLOCK_STATE
,
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED
,
&
req
,
sizeof
(
req
),
&
resp
,
sizeof
(
resp
),
&
xfer
);
if
(
ret
)
{
ERROR
(
"Message alloc failed (%d)
\n
"
,
ret
);
return
ret
;
}
req
.
dev_id
=
dev_id
;
req
.
clk_id
=
clk_id
;
ret
=
ti_sci_do_xfer
(
&
xfer
);
if
(
ret
)
{
ERROR
(
"Transfer send failed (%d)
\n
"
,
ret
);
return
ret
;
}
if
(
!
ti_sci_is_response_ack
(
&
resp
))
return
-
ENODEV
;
if
(
programmed_state
)
*
programmed_state
=
resp
.
programmed_state
;
if
(
current_state
)
*
current_state
=
resp
.
current_state
;
return
0
;
}
/**
* ti_sci_clock_get() - Get control of a clock from TI SCI
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
* Each device has its own set of clock inputs. This indexes
* which clock input to modify.
* @needs_ssc: 'true' iff Spread Spectrum clock is desired
* @can_change_freq: 'true' iff frequency change is desired
* @enable_input_term: 'true' iff input termination is desired
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_clock_get
(
uint32_t
dev_id
,
uint8_t
clk_id
,
bool
needs_ssc
,
bool
can_change_freq
,
bool
enable_input_term
)
{
uint32_t
flags
=
0
;
flags
|=
needs_ssc
?
MSG_FLAG_CLOCK_ALLOW_SSC
:
0
;
flags
|=
can_change_freq
?
MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE
:
0
;
flags
|=
enable_input_term
?
MSG_FLAG_CLOCK_INPUT_TERM
:
0
;
return
ti_sci_clock_set_state
(
dev_id
,
clk_id
,
flags
,
MSG_CLOCK_SW_STATE_REQ
);
}
/**
* ti_sci_clock_idle() - Idle a clock which is in our control
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
* Each device has its own set of clock inputs. This indexes
* which clock input to modify.
*
* NOTE: This clock must have been requested by get_clock previously.
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_clock_idle
(
uint32_t
dev_id
,
uint8_t
clk_id
)
{
return
ti_sci_clock_set_state
(
dev_id
,
clk_id
,
0
,
MSG_CLOCK_SW_STATE_UNREQ
);
}
/**
* ti_sci_clock_put() - Release a clock from our control
*
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
* Each device has its own set of clock inputs. This indexes
* which clock input to modify.
*
* NOTE: This clock must have been requested by get_clock previously.
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_clock_put
(
uint32_t
dev_id
,
uint8_t
clk_id
)
{
return
ti_sci_clock_set_state
(
dev_id
,
clk_id
,
0
,
MSG_CLOCK_SW_STATE_AUTO
);
}
/**
* ti_sci_clock_is_auto() - Is the clock being auto managed
*
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
* Each device has its own set of clock inputs. This indexes
* which clock input to modify.
* @req_state: state indicating if the clock is auto managed
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_clock_is_auto
(
uint32_t
dev_id
,
uint8_t
clk_id
,
bool
*
req_state
)
{
uint8_t
state
=
0
;
int
ret
;
if
(
!
req_state
)
return
-
EINVAL
;
ret
=
ti_sci_clock_get_state
(
dev_id
,
clk_id
,
&
state
,
NULL
);
if
(
ret
)
return
ret
;
*
req_state
=
(
state
==
MSG_CLOCK_SW_STATE_AUTO
);
return
0
;
}
/**
* ti_sci_clock_is_on() - Is the clock ON
*
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
* Each device has its own set of clock inputs. This indexes
* which clock input to modify.
* @req_state: state indicating if the clock is managed by us and enabled
* @curr_state: state indicating if the clock is ready for operation
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_clock_is_on
(
uint32_t
dev_id
,
uint8_t
clk_id
,
bool
*
req_state
,
bool
*
curr_state
)
{
uint8_t
c_state
=
0
,
r_state
=
0
;
int
ret
;
if
(
!
req_state
&&
!
curr_state
)
return
-
EINVAL
;
ret
=
ti_sci_clock_get_state
(
dev_id
,
clk_id
,
&
r_state
,
&
c_state
);
if
(
ret
)
return
ret
;
if
(
req_state
)
*
req_state
=
(
r_state
==
MSG_CLOCK_SW_STATE_REQ
);
if
(
curr_state
)
*
curr_state
=
(
c_state
==
MSG_CLOCK_HW_STATE_READY
);
return
0
;
}
/**
* ti_sci_clock_is_off() - Is the clock OFF
*
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
* Each device has its own set of clock inputs. This indexes
* which clock input to modify.
* @req_state: state indicating if the clock is managed by us and disabled
* @curr_state: state indicating if the clock is NOT ready for operation
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_clock_is_off
(
uint32_t
dev_id
,
uint8_t
clk_id
,
bool
*
req_state
,
bool
*
curr_state
)
{
uint8_t
c_state
=
0
,
r_state
=
0
;
int
ret
;
if
(
!
req_state
&&
!
curr_state
)
return
-
EINVAL
;
ret
=
ti_sci_clock_get_state
(
dev_id
,
clk_id
,
&
r_state
,
&
c_state
);
if
(
ret
)
return
ret
;
if
(
req_state
)
*
req_state
=
(
r_state
==
MSG_CLOCK_SW_STATE_UNREQ
);
if
(
curr_state
)
*
curr_state
=
(
c_state
==
MSG_CLOCK_HW_STATE_NOT_READY
);
return
0
;
}
/**
* ti_sci_clock_set_parent() - Set the clock source of a specific device clock
*
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
* Each device has its own set of clock inputs. This indexes
* which clock input to modify.
* @parent_id: Parent clock identifier to set
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_clock_set_parent
(
uint32_t
dev_id
,
uint8_t
clk_id
,
uint8_t
parent_id
)
{
struct
ti_sci_msg_req_set_clock_parent
req
;
struct
ti_sci_msg_hdr
resp
;
struct
ti_sci_xfer
xfer
;
int
ret
;
ret
=
ti_sci_setup_one_xfer
(
TI_SCI_MSG_SET_CLOCK_PARENT
,
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED
,
&
req
,
sizeof
(
req
),
&
resp
,
sizeof
(
resp
),
&
xfer
);
if
(
ret
)
{
ERROR
(
"Message alloc failed (%d)
\n
"
,
ret
);
return
ret
;
}
req
.
dev_id
=
dev_id
;
req
.
clk_id
=
clk_id
;
req
.
parent_id
=
parent_id
;
ret
=
ti_sci_do_xfer
(
&
xfer
);
if
(
ret
)
{
ERROR
(
"Transfer send failed (%d)
\n
"
,
ret
);
return
ret
;
}
if
(
!
ti_sci_is_response_ack
(
&
resp
))
return
-
ENODEV
;
return
0
;
}
/**
* ti_sci_clock_get_parent() - Get current parent clock source
*
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
* Each device has its own set of clock inputs. This indexes
* which clock input to modify.
* @parent_id: Current clock parent
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_clock_get_parent
(
uint32_t
dev_id
,
uint8_t
clk_id
,
uint8_t
*
parent_id
)
{
struct
ti_sci_msg_req_get_clock_parent
req
;
struct
ti_sci_msg_resp_get_clock_parent
resp
;
struct
ti_sci_xfer
xfer
;
int
ret
;
ret
=
ti_sci_setup_one_xfer
(
TI_SCI_MSG_GET_CLOCK_PARENT
,
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED
,
&
req
,
sizeof
(
req
),
&
resp
,
sizeof
(
resp
),
&
xfer
);
if
(
ret
)
{
ERROR
(
"Message alloc failed (%d)
\n
"
,
ret
);
return
ret
;
}
req
.
dev_id
=
dev_id
;
req
.
clk_id
=
clk_id
;
ret
=
ti_sci_do_xfer
(
&
xfer
);
if
(
ret
)
{
ERROR
(
"Transfer send failed (%d)
\n
"
,
ret
);
return
ret
;
}
if
(
!
ti_sci_is_response_ack
(
&
resp
))
return
-
ENODEV
;
*
parent_id
=
resp
.
parent_id
;
return
0
;
}
/**
* ti_sci_clock_get_num_parents() - Get num parents of the current clk source
*
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
* Each device has its own set of clock inputs. This indexes
* which clock input to modify.
* @num_parents: Returns he number of parents to the current clock.
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_clock_get_num_parents
(
uint32_t
dev_id
,
uint8_t
clk_id
,
uint8_t
*
num_parents
)
{
struct
ti_sci_msg_req_get_clock_num_parents
req
;
struct
ti_sci_msg_resp_get_clock_num_parents
resp
;
struct
ti_sci_xfer
xfer
;
int
ret
;
ret
=
ti_sci_setup_one_xfer
(
TI_SCI_MSG_GET_NUM_CLOCK_PARENTS
,
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED
,
&
req
,
sizeof
(
req
),
&
resp
,
sizeof
(
resp
),
&
xfer
);
if
(
ret
)
{
ERROR
(
"Message alloc failed (%d)
\n
"
,
ret
);
return
ret
;
}
req
.
dev_id
=
dev_id
;
req
.
clk_id
=
clk_id
;
ret
=
ti_sci_do_xfer
(
&
xfer
);
if
(
ret
)
{
ERROR
(
"Transfer send failed (%d)
\n
"
,
ret
);
return
ret
;
}
if
(
!
ti_sci_is_response_ack
(
&
resp
))
return
-
ENODEV
;
*
num_parents
=
resp
.
num_parents
;
return
0
;
}
/**
* ti_sci_clock_get_match_freq() - Find a good match for frequency
*
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
* Each device has its own set of clock inputs. This indexes
* which clock input to modify.
* @min_freq: The minimum allowable frequency in Hz. This is the minimum
* allowable programmed frequency and does not account for clock
* tolerances and jitter.
* @target_freq: The target clock frequency in Hz. A frequency will be
* processed as close to this target frequency as possible.
* @max_freq: The maximum allowable frequency in Hz. This is the maximum
* allowable programmed frequency and does not account for clock
* tolerances and jitter.
* @match_freq: Frequency match in Hz response.
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_clock_get_match_freq
(
uint32_t
dev_id
,
uint8_t
clk_id
,
uint64_t
min_freq
,
uint64_t
target_freq
,
uint64_t
max_freq
,
uint64_t
*
match_freq
)
{
struct
ti_sci_msg_req_query_clock_freq
req
;
struct
ti_sci_msg_resp_query_clock_freq
resp
;
struct
ti_sci_xfer
xfer
;
int
ret
;
ret
=
ti_sci_setup_one_xfer
(
TI_SCI_MSG_QUERY_CLOCK_FREQ
,
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED
,
&
req
,
sizeof
(
req
),
&
resp
,
sizeof
(
resp
),
&
xfer
);
if
(
ret
)
{
ERROR
(
"Message alloc failed (%d)
\n
"
,
ret
);
return
ret
;
}
req
.
dev_id
=
dev_id
;
req
.
clk_id
=
clk_id
;
req
.
min_freq_hz
=
min_freq
;
req
.
target_freq_hz
=
target_freq
;
req
.
max_freq_hz
=
max_freq
;
ret
=
ti_sci_do_xfer
(
&
xfer
);
if
(
ret
)
{
ERROR
(
"Transfer send failed (%d)
\n
"
,
ret
);
return
ret
;
}
if
(
!
ti_sci_is_response_ack
(
&
resp
))
return
-
ENODEV
;
*
match_freq
=
resp
.
freq_hz
;
return
0
;
}
/**
* ti_sci_clock_set_freq() - Set a frequency for clock
*
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
* Each device has its own set of clock inputs. This indexes
* which clock input to modify.
* @min_freq: The minimum allowable frequency in Hz. This is the minimum
* allowable programmed frequency and does not account for clock
* tolerances and jitter.
* @target_freq: The target clock frequency in Hz. A frequency will be
* processed as close to this target frequency as possible.
* @max_freq: The maximum allowable frequency in Hz. This is the maximum
* allowable programmed frequency and does not account for clock
* tolerances and jitter.
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_clock_set_freq
(
uint32_t
dev_id
,
uint8_t
clk_id
,
uint64_t
min_freq
,
uint64_t
target_freq
,
uint64_t
max_freq
)
{
struct
ti_sci_msg_req_set_clock_freq
req
;
struct
ti_sci_msg_hdr
resp
;
struct
ti_sci_xfer
xfer
;
int
ret
;
ret
=
ti_sci_setup_one_xfer
(
TI_SCI_MSG_SET_CLOCK_FREQ
,
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED
,
&
req
,
sizeof
(
req
),
&
resp
,
sizeof
(
resp
),
&
xfer
);
if
(
ret
)
{
ERROR
(
"Message alloc failed (%d)
\n
"
,
ret
);
return
ret
;
}
req
.
dev_id
=
dev_id
;
req
.
clk_id
=
clk_id
;
req
.
min_freq_hz
=
min_freq
;
req
.
target_freq_hz
=
target_freq
;
req
.
max_freq_hz
=
max_freq
;
ret
=
ti_sci_do_xfer
(
&
xfer
);
if
(
ret
)
{
ERROR
(
"Transfer send failed (%d)
\n
"
,
ret
);
return
ret
;
}
if
(
!
ti_sci_is_response_ack
(
&
resp
))
return
-
ENODEV
;
return
0
;
}
/**
* ti_sci_clock_get_freq() - Get current frequency
*
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
* Each device has its own set of clock inputs. This indexes
* which clock input to modify.
* @freq: Currently frequency in Hz
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_clock_get_freq
(
uint32_t
dev_id
,
uint8_t
clk_id
,
uint64_t
*
freq
)
{
struct
ti_sci_msg_req_get_clock_freq
req
;
struct
ti_sci_msg_resp_get_clock_freq
resp
;
struct
ti_sci_xfer
xfer
;
int
ret
;
ret
=
ti_sci_setup_one_xfer
(
TI_SCI_MSG_GET_CLOCK_FREQ
,
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED
,
&
req
,
sizeof
(
req
),
&
resp
,
sizeof
(
resp
),
&
xfer
);
if
(
ret
)
{
ERROR
(
"Message alloc failed (%d)
\n
"
,
ret
);
return
ret
;
}
req
.
dev_id
=
dev_id
;
req
.
clk_id
=
clk_id
;
ret
=
ti_sci_do_xfer
(
&
xfer
);
if
(
ret
)
{
ERROR
(
"Transfer send failed (%d)
\n
"
,
ret
);
return
ret
;
}
if
(
!
ti_sci_is_response_ack
(
&
resp
))
return
-
ENODEV
;
*
freq
=
resp
.
freq_hz
;
return
0
;
}
/**
* ti_sci_core_reboot() - Command to request system reset
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_core_reboot
(
void
)
{
struct
ti_sci_msg_req_reboot
req
;
struct
ti_sci_msg_hdr
resp
;
struct
ti_sci_xfer
xfer
;
int
ret
;
ret
=
ti_sci_setup_one_xfer
(
TI_SCI_MSG_SYS_RESET
,
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED
,
&
req
,
sizeof
(
req
),
&
resp
,
sizeof
(
resp
),
&
xfer
);
if
(
ret
)
{
ERROR
(
"Message alloc failed (%d)
\n
"
,
ret
);
return
ret
;
}
ret
=
ti_sci_do_xfer
(
&
xfer
);
if
(
ret
)
{
ERROR
(
"Transfer send failed (%d)
\n
"
,
ret
);
return
ret
;
}
if
(
!
ti_sci_is_response_ack
(
&
resp
))
return
-
ENODEV
;
return
0
;
}
/**
* ti_sci_proc_request() - Request a physical processor control
*
* @proc_id: Processor ID this request is for
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_proc_request
(
uint8_t
proc_id
)
{
struct
ti_sci_msg_req_proc_request
req
;
struct
ti_sci_msg_hdr
resp
;
struct
ti_sci_xfer
xfer
;
int
ret
;
ret
=
ti_sci_setup_one_xfer
(
TISCI_MSG_PROC_REQUEST
,
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED
,
&
req
,
sizeof
(
req
),
&
resp
,
sizeof
(
resp
),
&
xfer
);
if
(
ret
)
{
ERROR
(
"Message alloc failed (%d)
\n
"
,
ret
);
return
ret
;
}
req
.
processor_id
=
proc_id
;
ret
=
ti_sci_do_xfer
(
&
xfer
);
if
(
ret
)
{
ERROR
(
"Transfer send failed (%d)
\n
"
,
ret
);
return
ret
;
}
if
(
!
ti_sci_is_response_ack
(
&
resp
))
return
-
ENODEV
;
return
0
;
}
/**
* ti_sci_proc_release() - Release a physical processor control
*
* @proc_id: Processor ID this request is for
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_proc_release
(
uint8_t
proc_id
)
{
struct
ti_sci_msg_req_proc_release
req
;
struct
ti_sci_msg_hdr
resp
;
struct
ti_sci_xfer
xfer
;
int
ret
;
ret
=
ti_sci_setup_one_xfer
(
TISCI_MSG_PROC_RELEASE
,
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED
,
&
req
,
sizeof
(
req
),
&
resp
,
sizeof
(
resp
),
&
xfer
);
if
(
ret
)
{
ERROR
(
"Message alloc failed (%d)
\n
"
,
ret
);
return
ret
;
}
req
.
processor_id
=
proc_id
;
ret
=
ti_sci_do_xfer
(
&
xfer
);
if
(
ret
)
{
ERROR
(
"Transfer send failed (%d)
\n
"
,
ret
);
return
ret
;
}
if
(
!
ti_sci_is_response_ack
(
&
resp
))
return
-
ENODEV
;
return
0
;
}
/**
* ti_sci_proc_handover() - Handover a physical processor control to a host in
* the processor's access control list.
*
* @proc_id: Processor ID this request is for
* @host_id: Host ID to get the control of the processor
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_proc_handover
(
uint8_t
proc_id
,
uint8_t
host_id
)
{
struct
ti_sci_msg_req_proc_handover
req
;
struct
ti_sci_msg_hdr
resp
;
struct
ti_sci_xfer
xfer
;
int
ret
;
ret
=
ti_sci_setup_one_xfer
(
TISCI_MSG_PROC_HANDOVER
,
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED
,
&
req
,
sizeof
(
req
),
&
resp
,
sizeof
(
resp
),
&
xfer
);
if
(
ret
)
{
ERROR
(
"Message alloc failed (%d)
\n
"
,
ret
);
return
ret
;
}
req
.
processor_id
=
proc_id
;
req
.
host_id
=
host_id
;
ret
=
ti_sci_do_xfer
(
&
xfer
);
if
(
ret
)
{
ERROR
(
"Transfer send failed (%d)
\n
"
,
ret
);
return
ret
;
}
if
(
!
ti_sci_is_response_ack
(
&
resp
))
return
-
ENODEV
;
return
0
;
}
/**
* ti_sci_proc_set_boot_cfg() - Set the processor boot configuration flags
*
* @proc_id: Processor ID this request is for
* @config_flags_set: Configuration flags to be set
* @config_flags_clear: Configuration flags to be cleared
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_proc_set_boot_cfg
(
uint8_t
proc_id
,
uint64_t
bootvector
,
uint32_t
config_flags_set
,
uint32_t
config_flags_clear
)
{
struct
ti_sci_msg_req_set_proc_boot_config
req
;
struct
ti_sci_msg_hdr
resp
;
struct
ti_sci_xfer
xfer
;
int
ret
;
ret
=
ti_sci_setup_one_xfer
(
TISCI_MSG_SET_PROC_BOOT_CONFIG
,
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED
,
&
req
,
sizeof
(
req
),
&
resp
,
sizeof
(
resp
),
&
xfer
);
if
(
ret
)
{
ERROR
(
"Message alloc failed (%d)
\n
"
,
ret
);
return
ret
;
}
req
.
processor_id
=
proc_id
;
req
.
bootvector_low
=
bootvector
&
TISCI_ADDR_LOW_MASK
;
req
.
bootvector_high
=
(
bootvector
&
TISCI_ADDR_HIGH_MASK
)
>>
TISCI_ADDR_HIGH_SHIFT
;
req
.
config_flags_set
=
config_flags_set
;
req
.
config_flags_clear
=
config_flags_clear
;
ret
=
ti_sci_do_xfer
(
&
xfer
);
if
(
ret
)
{
ERROR
(
"Transfer send failed (%d)
\n
"
,
ret
);
return
ret
;
}
if
(
!
ti_sci_is_response_ack
(
&
resp
))
return
-
ENODEV
;
return
0
;
}
/**
* ti_sci_proc_set_boot_ctrl() - Set the processor boot control flags
*
* @proc_id: Processor ID this request is for
* @control_flags_set: Control flags to be set
* @control_flags_clear: Control flags to be cleared
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_proc_set_boot_ctrl
(
uint8_t
proc_id
,
uint32_t
control_flags_set
,
uint32_t
control_flags_clear
)
{
struct
ti_sci_msg_req_set_proc_boot_ctrl
req
;
struct
ti_sci_msg_hdr
resp
;
struct
ti_sci_xfer
xfer
;
int
ret
;
ret
=
ti_sci_setup_one_xfer
(
TISCI_MSG_SET_PROC_BOOT_CTRL
,
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED
,
&
req
,
sizeof
(
req
),
&
resp
,
sizeof
(
resp
),
&
xfer
);
if
(
ret
)
{
ERROR
(
"Message alloc failed (%d)
\n
"
,
ret
);
return
ret
;
}
req
.
processor_id
=
proc_id
;
req
.
control_flags_set
=
control_flags_set
;
req
.
control_flags_clear
=
control_flags_clear
;
ret
=
ti_sci_do_xfer
(
&
xfer
);
if
(
ret
)
{
ERROR
(
"Transfer send failed (%d)
\n
"
,
ret
);
return
ret
;
}
if
(
!
ti_sci_is_response_ack
(
&
resp
))
return
-
ENODEV
;
return
0
;
}
/**
* ti_sci_proc_auth_boot_image() - Authenticate and load image and then set the
* processor configuration flags
*
* @proc_id: Processor ID this request is for
* @cert_addr: Memory address at which payload image certificate is located
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_proc_auth_boot_image
(
uint8_t
proc_id
,
uint64_t
cert_addr
)
{
struct
ti_sci_msg_req_proc_auth_boot_image
req
;
struct
ti_sci_msg_hdr
resp
;
struct
ti_sci_xfer
xfer
;
int
ret
;
ret
=
ti_sci_setup_one_xfer
(
TISCI_MSG_PROC_AUTH_BOOT_IMIAGE
,
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED
,
&
req
,
sizeof
(
req
),
&
resp
,
sizeof
(
resp
),
&
xfer
);
if
(
ret
)
{
ERROR
(
"Message alloc failed (%d)
\n
"
,
ret
);
return
ret
;
}
req
.
processor_id
=
proc_id
;
req
.
cert_addr_low
=
cert_addr
&
TISCI_ADDR_LOW_MASK
;
req
.
cert_addr_high
=
(
cert_addr
&
TISCI_ADDR_HIGH_MASK
)
>>
TISCI_ADDR_HIGH_SHIFT
;
ret
=
ti_sci_do_xfer
(
&
xfer
);
if
(
ret
)
{
ERROR
(
"Transfer send failed (%d)
\n
"
,
ret
);
return
ret
;
}
if
(
!
ti_sci_is_response_ack
(
&
resp
))
return
-
ENODEV
;
return
0
;
}
/**
* ti_sci_proc_get_boot_status() - Get the processor boot status
*
* @proc_id: Processor ID this request is for
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_proc_get_boot_status
(
uint8_t
proc_id
,
uint64_t
*
bv
,
uint32_t
*
cfg_flags
,
uint32_t
*
ctrl_flags
,
uint32_t
*
sts_flags
)
{
struct
ti_sci_msg_req_get_proc_boot_status
req
;
struct
ti_sci_msg_resp_get_proc_boot_status
resp
;
struct
ti_sci_xfer
xfer
;
int
ret
;
ret
=
ti_sci_setup_one_xfer
(
TISCI_MSG_GET_PROC_BOOT_STATUS
,
TI_SCI_FLAG_REQ_ACK_ON_PROCESSED
,
&
req
,
sizeof
(
req
),
&
resp
,
sizeof
(
resp
),
&
xfer
);
if
(
ret
)
{
ERROR
(
"Message alloc failed (%d)
\n
"
,
ret
);
return
ret
;
}
req
.
processor_id
=
proc_id
;
ret
=
ti_sci_do_xfer
(
&
xfer
);
if
(
ret
)
{
ERROR
(
"Transfer send failed (%d)
\n
"
,
ret
);
return
ret
;
}
if
(
!
ti_sci_is_response_ack
(
&
resp
))
return
-
ENODEV
;
*
bv
=
(
resp
.
bootvector_low
&
TISCI_ADDR_LOW_MASK
)
|
(((
uint64_t
)
resp
.
bootvector_high
<<
TISCI_ADDR_HIGH_SHIFT
)
&
TISCI_ADDR_HIGH_MASK
);
*
cfg_flags
=
resp
.
config_flags
;
*
ctrl_flags
=
resp
.
control_flags
;
*
sts_flags
=
resp
.
status_flags
;
return
0
;
}
/**
* ti_sci_init() - Basic initialization
*
* Return: 0 if all goes well, else appropriate error message
*/
int
ti_sci_init
(
void
)
{
struct
ti_sci_msg_resp_version
rev_info
;
int
ret
;
ret
=
ti_sci_get_revision
(
&
rev_info
);
if
(
ret
)
{
ERROR
(
"Unable to communicate with control firmware (%d)
\n
"
,
ret
);
return
ret
;
}
INFO
(
"SYSFW ABI: %d.%d (firmware rev 0x%04x '%s')
\n
"
,
rev_info
.
abi_major
,
rev_info
.
abi_minor
,
rev_info
.
firmware_revision
,
rev_info
.
firmware_description
);
return
0
;
}
plat/ti/k3/common/drivers/ti_sci/ti_sci.h
0 → 100644
View file @
a542faad
/*
* Texas Instruments System Control Interface API
* Based on Linux and U-Boot implementation
*
* Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __TI_SCI_H
#define __TI_SCI_H
#include <stdint.h>
#include <stdbool.h>
/**
* Device control operations
*
* - ti_sci_device_set_state - Set device state helper
* @flags: flags to setup for the device
* @state: State to move the device to
* - ti_sci_device_get_state - Get device state helper
* @clcnt: Pointer to Context Loss Count
* @resets: pointer to resets
* @p_state: pointer to p_state
* @c_state: pointer to c_state
* - ti_sci_device_get - command to request for device managed by TISCI
* - ti_sci_device_idle - Command to idle a device managed by TISCI
* - ti_sci_device_put - command to release a device managed by TISCI
* - ti_sci_device_is_valid - Is the device valid
* - ti_sci_device_get_clcnt - Get context loss counter
* @count: Pointer to Context Loss counter to populate
* - ti_sci_device_is_idle - Check if the device is requested to be idle
* @r_state: true if requested to be idle
* - ti_sci_device_is_stop - Check if the device is requested to be stopped
* @r_state: true if requested to be stopped
* @curr_state: true if currently stopped.
* - ti_sci_device_is_on - Check if the device is requested to be ON
* @r_state: true if requested to be ON
* @curr_state: true if currently ON and active
* - ti_sci_device_is_trans - Check if the device is currently transitioning
* @curr_state: true if currently transitioning.
* - ti_sci_device_set_resets - Command to set resets for
* device managed by TISCI
* @reset_state: Device specific reset bit field
* - ti_sci_device_get_resets - Get reset state for device managed by TISCI
* @reset_state: Pointer to reset state to populate
*
* NOTE: for all these functions, the following are generic in nature:
* @id: Device Identifier
* Returns 0 for successful request, else returns corresponding error message.
*
* Request for the device - NOTE: the client MUST maintain integrity of
* usage count by balancing get_device with put_device. No refcounting is
* managed by driver for that purpose.
*/
int
ti_sci_device_set_state
(
uint32_t
id
,
uint32_t
flags
,
uint8_t
state
);
int
ti_sci_device_get_state
(
uint32_t
id
,
uint32_t
*
clcnt
,
uint32_t
*
resets
,
uint8_t
*
p_state
,
uint8_t
*
c_state
);
int
ti_sci_device_get
(
uint32_t
id
);
int
ti_sci_device_idle
(
uint32_t
id
);
int
ti_sci_device_put
(
uint32_t
id
);
int
ti_sci_device_is_valid
(
uint32_t
id
);
int
ti_sci_device_get_clcnt
(
uint32_t
id
,
uint32_t
*
count
);
int
ti_sci_device_is_idle
(
uint32_t
id
,
bool
*
r_state
);
int
ti_sci_device_is_stop
(
uint32_t
id
,
bool
*
r_state
,
bool
*
curr_state
);
int
ti_sci_device_is_on
(
uint32_t
id
,
bool
*
r_state
,
bool
*
curr_state
);
int
ti_sci_device_is_trans
(
uint32_t
id
,
bool
*
curr_state
);
int
ti_sci_device_set_resets
(
uint32_t
id
,
uint32_t
reset_state
);
int
ti_sci_device_get_resets
(
uint32_t
id
,
uint32_t
*
reset_state
);
/**
* Clock control operations
*
* - ti_sci_clock_set_state - Set clock state helper
* @flags: Header flags as needed
* @state: State to request for the clock.
* - ti_sci_clock_get_state - Get clock state helper
* @programmed_state: State requested for clock to move to
* @current_state: State that the clock is currently in
* - ti_sci_clock_get - Get control of a clock from TI SCI
* @needs_ssc: 'true' iff Spread Spectrum clock is desired
* @can_change_freq: 'true' iff frequency change is desired
* @enable_input_term: 'true' iff input termination is desired
* - ti_sci_clock_idle - Idle a clock which is in our control
* - ti_sci_clock_put - Release a clock from our control
* - ti_sci_clock_is_auto - Is the clock being auto managed
* @req_state: state indicating if the clock is auto managed
* - ti_sci_clock_is_on - Is the clock ON
* @req_state: state indicating if the clock is managed by us and enabled
* @curr_state: state indicating if the clock is ready for operation
* - ti_sci_clock_is_off - Is the clock OFF
* @req_state: state indicating if the clock is managed by us and disabled
* @curr_state: state indicating if the clock is NOT ready for operation
* - ti_sci_clock_set_parent - Set the clock source of a specific device clock
* @parent_id: Parent clock identifier to set
* - ti_sci_clock_get_parent - Get current parent clock source
* @parent_id: Current clock parent
* - ti_sci_clock_get_num_parents - Get num parents of the current clk source
* @num_parents: Returns he number of parents to the current clock.
* - ti_sci_clock_get_match_freq - Find a good match for frequency
* @match_freq: Frequency match in Hz response.
* - ti_sci_clock_set_freq - Set a frequency for clock
* - ti_sci_clock_get_freq - Get current frequency
* @freq: Currently frequency in Hz
*
* NOTE: for all these functions, the following are generic in nature:
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
* Each device has its own set of clock inputs. This indexes
* which clock input to modify.
* @min_freq: The minimum allowable frequency in Hz. This is the minimum
* allowable programmed frequency and does not account for clock
* tolerances and jitter.
* @target_freq: The target clock frequency in Hz. A frequency will be
* processed as close to this target frequency as possible.
* @max_freq: The maximum allowable frequency in Hz. This is the maximum
* allowable programmed frequency and does not account for clock
* tolerances and jitter.
* Returns 0 for successful request, else returns corresponding error message.
*
* Request for the clock - NOTE: the client MUST maintain integrity of
* usage count by balancing get_clock with put_clock. No refcounting is
* managed by driver for that purpose.
*/
int
ti_sci_clock_set_state
(
uint32_t
dev_id
,
uint8_t
clk_id
,
uint32_t
flags
,
uint8_t
state
);
int
ti_sci_clock_get_state
(
uint32_t
dev_id
,
uint8_t
clk_id
,
uint8_t
*
programmed_state
,
uint8_t
*
current_state
);
int
ti_sci_clock_get
(
uint32_t
dev_id
,
uint8_t
clk_id
,
bool
needs_ssc
,
bool
can_change_freq
,
bool
enable_input_term
);
int
ti_sci_clock_idle
(
uint32_t
dev_id
,
uint8_t
clk_id
);
int
ti_sci_clock_put
(
uint32_t
dev_id
,
uint8_t
clk_id
);
int
ti_sci_clock_is_auto
(
uint32_t
dev_id
,
uint8_t
clk_id
,
bool
*
req_state
);
int
ti_sci_clock_is_on
(
uint32_t
dev_id
,
uint8_t
clk_id
,
bool
*
req_state
,
bool
*
curr_state
);
int
ti_sci_clock_is_off
(
uint32_t
dev_id
,
uint8_t
clk_id
,
bool
*
req_state
,
bool
*
curr_state
);
int
ti_sci_clock_set_parent
(
uint32_t
dev_id
,
uint8_t
clk_id
,
uint8_t
parent_id
);
int
ti_sci_clock_get_parent
(
uint32_t
dev_id
,
uint8_t
clk_id
,
uint8_t
*
parent_id
);
int
ti_sci_clock_get_num_parents
(
uint32_t
dev_id
,
uint8_t
clk_id
,
uint8_t
*
num_parents
);
int
ti_sci_clock_get_match_freq
(
uint32_t
dev_id
,
uint8_t
clk_id
,
uint64_t
min_freq
,
uint64_t
target_freq
,
uint64_t
max_freq
,
uint64_t
*
match_freq
);
int
ti_sci_clock_set_freq
(
uint32_t
dev_id
,
uint8_t
clk_id
,
uint64_t
min_freq
,
uint64_t
target_freq
,
uint64_t
max_freq
);
int
ti_sci_clock_get_freq
(
uint32_t
dev_id
,
uint8_t
clk_id
,
uint64_t
*
freq
);
/**
* Core control operations
*
* - ti_sci_core_reboot() - Command to request system reset
*
* Return: 0 if all went well, else returns appropriate error value.
*/
int
ti_sci_core_reboot
(
void
);
/**
* Processor control operations
*
* - ti_sci_proc_request - Command to request a physical processor control
* - ti_sci_proc_release - Command to release a physical processor control
* - ti_sci_proc_handover - Command to handover a physical processor control to
* a host in the processor's access control list.
* @host_id: Host ID to get the control of the processor
* - ti_sci_proc_set_boot_cfg - Command to set the processor boot configuration flags
* @config_flags_set: Configuration flags to be set
* @config_flags_clear: Configuration flags to be cleared.
* - ti_sci_proc_set_boot_ctrl - Command to set the processor boot control flags
* @control_flags_set: Control flags to be set
* @control_flags_clear: Control flags to be cleared
* - ti_sci_proc_auth_boot_image - Command to authenticate and load the image
* and then set the processor configuration flags.
* @cert_addr: Memory address at which payload image certificate is located.
* - ti_sci_proc_get_boot_status - Command to get the processor boot status
*
* NOTE: for all these functions, the following are generic in nature:
* @proc_id: Processor ID
* Returns 0 for successful request, else returns corresponding error message.
*/
int
ti_sci_proc_request
(
uint8_t
proc_id
);
int
ti_sci_proc_release
(
uint8_t
proc_id
);
int
ti_sci_proc_handover
(
uint8_t
proc_id
,
uint8_t
host_id
);
int
ti_sci_proc_set_boot_cfg
(
uint8_t
proc_id
,
uint64_t
bootvector
,
uint32_t
config_flags_set
,
uint32_t
config_flags_clear
);
int
ti_sci_proc_set_boot_ctrl
(
uint8_t
proc_id
,
uint32_t
control_flags_set
,
uint32_t
control_flags_clear
);
int
ti_sci_proc_auth_boot_image
(
uint8_t
proc_id
,
uint64_t
cert_addr
);
int
ti_sci_proc_get_boot_status
(
uint8_t
proc_id
,
uint64_t
*
bv
,
uint32_t
*
cfg_flags
,
uint32_t
*
ctrl_flags
,
uint32_t
*
sts_flags
);
/**
* ti_sci_init() - Basic initialization
*
* Return: 0 if all goes good, else appropriate error message.
*/
int
ti_sci_init
(
void
);
#endif
/* __TI_SCI_H */
plat/ti/k3/common/drivers/ti_sci/ti_sci_protocol.h
0 → 100644
View file @
a542faad
/*
* Texas Instruments System Control Interface (TISCI) Protocol
*
* Communication protocol with TI SCI hardware
* The system works in a message response protocol
* See: http://processors.wiki.ti.com/index.php/TISCI for details
*
* Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __TI_SCI_PROTOCOL_H
#define __TI_SCI_PROTOCOL_H
#include <stdint.h>
/* Generic Messages */
#define TI_SCI_MSG_ENABLE_WDT 0x0000
#define TI_SCI_MSG_WAKE_RESET 0x0001
#define TI_SCI_MSG_VERSION 0x0002
#define TI_SCI_MSG_WAKE_REASON 0x0003
#define TI_SCI_MSG_GOODBYE 0x0004
#define TI_SCI_MSG_SYS_RESET 0x0005
/* Device requests */
#define TI_SCI_MSG_SET_DEVICE_STATE 0x0200
#define TI_SCI_MSG_GET_DEVICE_STATE 0x0201
#define TI_SCI_MSG_SET_DEVICE_RESETS 0x0202
/* Clock requests */
#define TI_SCI_MSG_SET_CLOCK_STATE 0x0100
#define TI_SCI_MSG_GET_CLOCK_STATE 0x0101
#define TI_SCI_MSG_SET_CLOCK_PARENT 0x0102
#define TI_SCI_MSG_GET_CLOCK_PARENT 0x0103
#define TI_SCI_MSG_GET_NUM_CLOCK_PARENTS 0x0104
#define TI_SCI_MSG_SET_CLOCK_FREQ 0x010c
#define TI_SCI_MSG_QUERY_CLOCK_FREQ 0x010d
#define TI_SCI_MSG_GET_CLOCK_FREQ 0x010e
/* Processor Control Messages */
#define TISCI_MSG_PROC_REQUEST 0xc000
#define TISCI_MSG_PROC_RELEASE 0xc001
#define TISCI_MSG_PROC_HANDOVER 0xc005
#define TISCI_MSG_SET_PROC_BOOT_CONFIG 0xc100
#define TISCI_MSG_SET_PROC_BOOT_CTRL 0xc101
#define TISCI_MSG_PROC_AUTH_BOOT_IMIAGE 0xc120
#define TISCI_MSG_GET_PROC_BOOT_STATUS 0xc400
/**
* struct ti_sci_msg_hdr - Generic Message Header for All messages and responses
* @type: Type of messages: One of TI_SCI_MSG* values
* @host: Host of the message
* @seq: Message identifier indicating a transfer sequence
* @flags: Flag for the message
*/
struct
ti_sci_msg_hdr
{
uint16_t
type
;
uint8_t
host
;
uint8_t
seq
;
#define TI_SCI_MSG_FLAG(val) (1 << (val))
#define TI_SCI_FLAG_REQ_GENERIC_NORESPONSE 0x0
#define TI_SCI_FLAG_REQ_ACK_ON_RECEIVED TI_SCI_MSG_FLAG(0)
#define TI_SCI_FLAG_REQ_ACK_ON_PROCESSED TI_SCI_MSG_FLAG(1)
#define TI_SCI_FLAG_RESP_GENERIC_NACK 0x0
#define TI_SCI_FLAG_RESP_GENERIC_ACK TI_SCI_MSG_FLAG(1)
/* Additional Flags */
uint32_t
flags
;
}
__packed
;
/**
* struct ti_sci_msg_resp_version - Response for a message
* @hdr: Generic header
* @firmware_description: String describing the firmware
* @firmware_revision: Firmware revision
* @abi_major: Major version of the ABI that firmware supports
* @abi_minor: Minor version of the ABI that firmware supports
*
* In general, ABI version changes follow the rule that minor version increments
* are backward compatible. Major revision changes in ABI may not be
* backward compatible.
*
* Response to a generic message with message type TI_SCI_MSG_VERSION
*/
struct
ti_sci_msg_resp_version
{
struct
ti_sci_msg_hdr
hdr
;
#define FIRMWARE_DESCRIPTION_LENGTH 32
char
firmware_description
[
FIRMWARE_DESCRIPTION_LENGTH
];
uint16_t
firmware_revision
;
uint8_t
abi_major
;
uint8_t
abi_minor
;
}
__packed
;
/**
* struct ti_sci_msg_req_reboot - Reboot the SoC
* @hdr: Generic Header
*
* Request type is TI_SCI_MSG_SYS_RESET, responded with a generic
* ACK/NACK message.
*/
struct
ti_sci_msg_req_reboot
{
struct
ti_sci_msg_hdr
hdr
;
}
__packed
;
/**
* struct ti_sci_msg_req_set_device_state - Set the desired state of the device
* @hdr: Generic header
* @id: Indicates which device to modify
* @reserved: Reserved space in message, must be 0 for backward compatibility
* @state: The desired state of the device.
*
* Certain flags can also be set to alter the device state:
* + MSG_FLAG_DEVICE_WAKE_ENABLED - Configure the device to be a wake source.
* The meaning of this flag will vary slightly from device to device and from
* SoC to SoC but it generally allows the device to wake the SoC out of deep
* suspend states.
* + MSG_FLAG_DEVICE_RESET_ISO - Enable reset isolation for this device.
* + MSG_FLAG_DEVICE_EXCLUSIVE - Claim this device exclusively. When passed
* with STATE_RETENTION or STATE_ON, it will claim the device exclusively.
* If another host already has this device set to STATE_RETENTION or STATE_ON,
* the message will fail. Once successful, other hosts attempting to set
* STATE_RETENTION or STATE_ON will fail.
*
* Request type is TI_SCI_MSG_SET_DEVICE_STATE, responded with a generic
* ACK/NACK message.
*/
struct
ti_sci_msg_req_set_device_state
{
/* Additional hdr->flags options */
#define MSG_FLAG_DEVICE_WAKE_ENABLED TI_SCI_MSG_FLAG(8)
#define MSG_FLAG_DEVICE_RESET_ISO TI_SCI_MSG_FLAG(9)
#define MSG_FLAG_DEVICE_EXCLUSIVE TI_SCI_MSG_FLAG(10)
struct
ti_sci_msg_hdr
hdr
;
uint32_t
id
;
uint32_t
reserved
;
#define MSG_DEVICE_SW_STATE_AUTO_OFF 0
#define MSG_DEVICE_SW_STATE_RETENTION 1
#define MSG_DEVICE_SW_STATE_ON 2
uint8_t
state
;
}
__packed
;
/**
* struct ti_sci_msg_req_get_device_state - Request to get device.
* @hdr: Generic header
* @id: Device Identifier
*
* Request type is TI_SCI_MSG_GET_DEVICE_STATE, responded device state
* information
*/
struct
ti_sci_msg_req_get_device_state
{
struct
ti_sci_msg_hdr
hdr
;
uint32_t
id
;
}
__packed
;
/**
* struct ti_sci_msg_resp_get_device_state - Response to get device request.
* @hdr: Generic header
* @context_loss_count: Indicates how many times the device has lost context. A
* driver can use this monotonic counter to determine if the device has
* lost context since the last time this message was exchanged.
* @resets: Programmed state of the reset lines.
* @programmed_state: The state as programmed by set_device.
* - Uses the MSG_DEVICE_SW_* macros
* @current_state: The actual state of the hardware.
*
* Response to request TI_SCI_MSG_GET_DEVICE_STATE.
*/
struct
ti_sci_msg_resp_get_device_state
{
struct
ti_sci_msg_hdr
hdr
;
uint32_t
context_loss_count
;
uint32_t
resets
;
uint8_t
programmed_state
;
#define MSG_DEVICE_HW_STATE_OFF 0
#define MSG_DEVICE_HW_STATE_ON 1
#define MSG_DEVICE_HW_STATE_TRANS 2
uint8_t
current_state
;
}
__packed
;
/**
* struct ti_sci_msg_req_set_device_resets - Set the desired resets
* configuration of the device
* @hdr: Generic header
* @id: Indicates which device to modify
* @resets: A bit field of resets for the device. The meaning, behavior,
* and usage of the reset flags are device specific. 0 for a bit
* indicates releasing the reset represented by that bit while 1
* indicates keeping it held.
*
* Request type is TI_SCI_MSG_SET_DEVICE_RESETS, responded with a generic
* ACK/NACK message.
*/
struct
ti_sci_msg_req_set_device_resets
{
struct
ti_sci_msg_hdr
hdr
;
uint32_t
id
;
uint32_t
resets
;
}
__packed
;
/**
* struct ti_sci_msg_req_set_clock_state - Request to setup a Clock state
* @hdr: Generic Header, Certain flags can be set specific to the clocks:
* MSG_FLAG_CLOCK_ALLOW_SSC: Allow this clock to be modified
* via spread spectrum clocking.
* MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE: Allow this clock's
* frequency to be changed while it is running so long as it
* is within the min/max limits.
* MSG_FLAG_CLOCK_INPUT_TERM: Enable input termination, this
* is only applicable to clock inputs on the SoC pseudo-device.
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
* Each device has it's own set of clock inputs. This indexes
* which clock input to modify.
* @request_state: Request the state for the clock to be set to.
* MSG_CLOCK_SW_STATE_UNREQ: The IP does not require this clock,
* it can be disabled, regardless of the state of the device
* MSG_CLOCK_SW_STATE_AUTO: Allow the System Controller to
* automatically manage the state of this clock. If the device
* is enabled, then the clock is enabled. If the device is set
* to off or retention, then the clock is internally set as not
* being required by the device.(default)
* MSG_CLOCK_SW_STATE_REQ: Configure the clock to be enabled,
* regardless of the state of the device.
*
* Normally, all required clocks are managed by TISCI entity, this is used
* only for specific control *IF* required. Auto managed state is
* MSG_CLOCK_SW_STATE_AUTO, in other states, TISCI entity assume remote
* will explicitly control.
*
* Request type is TI_SCI_MSG_SET_CLOCK_STATE, response is a generic
* ACK or NACK message.
*/
struct
ti_sci_msg_req_set_clock_state
{
/* Additional hdr->flags options */
#define MSG_FLAG_CLOCK_ALLOW_SSC TI_SCI_MSG_FLAG(8)
#define MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE TI_SCI_MSG_FLAG(9)
#define MSG_FLAG_CLOCK_INPUT_TERM TI_SCI_MSG_FLAG(10)
struct
ti_sci_msg_hdr
hdr
;
uint32_t
dev_id
;
uint8_t
clk_id
;
#define MSG_CLOCK_SW_STATE_UNREQ 0
#define MSG_CLOCK_SW_STATE_AUTO 1
#define MSG_CLOCK_SW_STATE_REQ 2
uint8_t
request_state
;
}
__packed
;
/**
* struct ti_sci_msg_req_get_clock_state - Request for clock state
* @hdr: Generic Header
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
* Each device has it's own set of clock inputs. This indexes
* which clock input to get state of.
*
* Request type is TI_SCI_MSG_GET_CLOCK_STATE, response is state
* of the clock
*/
struct
ti_sci_msg_req_get_clock_state
{
struct
ti_sci_msg_hdr
hdr
;
uint32_t
dev_id
;
uint8_t
clk_id
;
}
__packed
;
/**
* struct ti_sci_msg_resp_get_clock_state - Response to get clock state
* @hdr: Generic Header
* @programmed_state: Any programmed state of the clock. This is one of
* MSG_CLOCK_SW_STATE* values.
* @current_state: Current state of the clock. This is one of:
* MSG_CLOCK_HW_STATE_NOT_READY: Clock is not ready
* MSG_CLOCK_HW_STATE_READY: Clock is ready
*
* Response to TI_SCI_MSG_GET_CLOCK_STATE.
*/
struct
ti_sci_msg_resp_get_clock_state
{
struct
ti_sci_msg_hdr
hdr
;
uint8_t
programmed_state
;
#define MSG_CLOCK_HW_STATE_NOT_READY 0
#define MSG_CLOCK_HW_STATE_READY 1
uint8_t
current_state
;
}
__packed
;
/**
* struct ti_sci_msg_req_set_clock_parent - Set the clock parent
* @hdr: Generic Header
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
* Each device has it's own set of clock inputs. This indexes
* which clock input to modify.
* @parent_id: The new clock parent is selectable by an index via this
* parameter.
*
* Request type is TI_SCI_MSG_SET_CLOCK_PARENT, response is generic
* ACK / NACK message.
*/
struct
ti_sci_msg_req_set_clock_parent
{
struct
ti_sci_msg_hdr
hdr
;
uint32_t
dev_id
;
uint8_t
clk_id
;
uint8_t
parent_id
;
}
__packed
;
/**
* struct ti_sci_msg_req_get_clock_parent - Get the clock parent
* @hdr: Generic Header
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
* Each device has it's own set of clock inputs. This indexes
* which clock input to get the parent for.
*
* Request type is TI_SCI_MSG_GET_CLOCK_PARENT, response is parent information
*/
struct
ti_sci_msg_req_get_clock_parent
{
struct
ti_sci_msg_hdr
hdr
;
uint32_t
dev_id
;
uint8_t
clk_id
;
}
__packed
;
/**
* struct ti_sci_msg_resp_get_clock_parent - Response with clock parent
* @hdr: Generic Header
* @parent_id: The current clock parent
*
* Response to TI_SCI_MSG_GET_CLOCK_PARENT.
*/
struct
ti_sci_msg_resp_get_clock_parent
{
struct
ti_sci_msg_hdr
hdr
;
uint8_t
parent_id
;
}
__packed
;
/**
* struct ti_sci_msg_req_get_clock_num_parents - Request to get clock parents
* @hdr: Generic header
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
*
* This request provides information about how many clock parent options
* are available for a given clock to a device. This is typically used
* for input clocks.
*
* Request type is TI_SCI_MSG_GET_NUM_CLOCK_PARENTS, response is appropriate
* message, or NACK in case of inability to satisfy request.
*/
struct
ti_sci_msg_req_get_clock_num_parents
{
struct
ti_sci_msg_hdr
hdr
;
uint32_t
dev_id
;
uint8_t
clk_id
;
}
__packed
;
/**
* struct ti_sci_msg_resp_get_clock_num_parents - Response for get clk parents
* @hdr: Generic header
* @num_parents: Number of clock parents
*
* Response to TI_SCI_MSG_GET_NUM_CLOCK_PARENTS
*/
struct
ti_sci_msg_resp_get_clock_num_parents
{
struct
ti_sci_msg_hdr
hdr
;
uint8_t
num_parents
;
}
__packed
;
/**
* struct ti_sci_msg_req_query_clock_freq - Request to query a frequency
* @hdr: Generic Header
* @dev_id: Device identifier this request is for
* @min_freq_hz: The minimum allowable frequency in Hz. This is the minimum
* allowable programmed frequency and does not account for clock
* tolerances and jitter.
* @target_freq_hz: The target clock frequency. A frequency will be found
* as close to this target frequency as possible.
* @max_freq_hz: The maximum allowable frequency in Hz. This is the maximum
* allowable programmed frequency and does not account for clock
* tolerances and jitter.
* @clk_id: Clock identifier for the device for this request.
*
* NOTE: Normally clock frequency management is automatically done by TISCI
* entity. In case of specific requests, TISCI evaluates capability to achieve
* requested frequency within provided range and responds with
* result message.
*
* Request type is TI_SCI_MSG_QUERY_CLOCK_FREQ, response is appropriate message,
* or NACK in case of inability to satisfy request.
*/
struct
ti_sci_msg_req_query_clock_freq
{
struct
ti_sci_msg_hdr
hdr
;
uint32_t
dev_id
;
uint64_t
min_freq_hz
;
uint64_t
target_freq_hz
;
uint64_t
max_freq_hz
;
uint8_t
clk_id
;
}
__packed
;
/**
* struct ti_sci_msg_resp_query_clock_freq - Response to a clock frequency query
* @hdr: Generic Header
* @freq_hz: Frequency that is the best match in Hz.
*
* Response to request type TI_SCI_MSG_QUERY_CLOCK_FREQ. NOTE: if the request
* cannot be satisfied, the message will be of type NACK.
*/
struct
ti_sci_msg_resp_query_clock_freq
{
struct
ti_sci_msg_hdr
hdr
;
uint64_t
freq_hz
;
}
__packed
;
/**
* struct ti_sci_msg_req_set_clock_freq - Request to setup a clock frequency
* @hdr: Generic Header
* @dev_id: Device identifier this request is for
* @min_freq_hz: The minimum allowable frequency in Hz. This is the minimum
* allowable programmed frequency and does not account for clock
* tolerances and jitter.
* @target_freq_hz: The target clock frequency. The clock will be programmed
* at a rate as close to this target frequency as possible.
* @max_freq_hz: The maximum allowable frequency in Hz. This is the maximum
* allowable programmed frequency and does not account for clock
* tolerances and jitter.
* @clk_id: Clock identifier for the device for this request.
*
* NOTE: Normally clock frequency management is automatically done by TISCI
* entity. In case of specific requests, TISCI evaluates capability to achieve
* requested range and responds with success/failure message.
*
* This sets the desired frequency for a clock within an allowable
* range. This message will fail on an enabled clock unless
* MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE is set for the clock. Additionally,
* if other clocks have their frequency modified due to this message,
* they also must have the MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE or be disabled.
*
* Calling set frequency on a clock input to the SoC pseudo-device will
* inform the PMMC of that clock's frequency. Setting a frequency of
* zero will indicate the clock is disabled.
*
* Calling set frequency on clock outputs from the SoC pseudo-device will
* function similarly to setting the clock frequency on a device.
*
* Request type is TI_SCI_MSG_SET_CLOCK_FREQ, response is a generic ACK/NACK
* message.
*/
struct
ti_sci_msg_req_set_clock_freq
{
struct
ti_sci_msg_hdr
hdr
;
uint32_t
dev_id
;
uint64_t
min_freq_hz
;
uint64_t
target_freq_hz
;
uint64_t
max_freq_hz
;
uint8_t
clk_id
;
}
__packed
;
/**
* struct ti_sci_msg_req_get_clock_freq - Request to get the clock frequency
* @hdr: Generic Header
* @dev_id: Device identifier this request is for
* @clk_id: Clock identifier for the device for this request.
*
* NOTE: Normally clock frequency management is automatically done by TISCI
* entity. In some cases, clock frequencies are configured by host.
*
* Request type is TI_SCI_MSG_GET_CLOCK_FREQ, responded with clock frequency
* that the clock is currently at.
*/
struct
ti_sci_msg_req_get_clock_freq
{
struct
ti_sci_msg_hdr
hdr
;
uint32_t
dev_id
;
uint8_t
clk_id
;
}
__packed
;
/**
* struct ti_sci_msg_resp_get_clock_freq - Response of clock frequency request
* @hdr: Generic Header
* @freq_hz: Frequency that the clock is currently on, in Hz.
*
* Response to request type TI_SCI_MSG_GET_CLOCK_FREQ.
*/
struct
ti_sci_msg_resp_get_clock_freq
{
struct
ti_sci_msg_hdr
hdr
;
uint64_t
freq_hz
;
}
__packed
;
#define TISCI_ADDR_LOW_MASK 0x00000000ffffffff
#define TISCI_ADDR_HIGH_MASK 0xffffffff00000000
#define TISCI_ADDR_HIGH_SHIFT 32
/**
* struct ti_sci_msg_req_proc_request - Request a processor
*
* @hdr: Generic Header
* @processor_id: ID of processor
*
* Request type is TISCI_MSG_PROC_REQUEST, response is a generic ACK/NACK
* message.
*/
struct
ti_sci_msg_req_proc_request
{
struct
ti_sci_msg_hdr
hdr
;
uint8_t
processor_id
;
}
__packed
;
/**
* struct ti_sci_msg_req_proc_release - Release a processor
*
* @hdr: Generic Header
* @processor_id: ID of processor
*
* Request type is TISCI_MSG_PROC_RELEASE, response is a generic ACK/NACK
* message.
*/
struct
ti_sci_msg_req_proc_release
{
struct
ti_sci_msg_hdr
hdr
;
uint8_t
processor_id
;
}
__packed
;
/**
* struct ti_sci_msg_req_proc_handover - Handover a processor to a host
*
* @hdr: Generic Header
* @processor_id: ID of processor
* @host_id: New Host we want to give control to
*
* Request type is TISCI_MSG_PROC_HANDOVER, response is a generic ACK/NACK
* message.
*/
struct
ti_sci_msg_req_proc_handover
{
struct
ti_sci_msg_hdr
hdr
;
uint8_t
processor_id
;
uint8_t
host_id
;
}
__packed
;
/* A53 Config Flags */
#define PROC_BOOT_CFG_FLAG_ARMV8_DBG_EN 0x00000001
#define PROC_BOOT_CFG_FLAG_ARMV8_DBG_NIDEN 0x00000002
#define PROC_BOOT_CFG_FLAG_ARMV8_DBG_SPIDEN 0x00000004
#define PROC_BOOT_CFG_FLAG_ARMV8_DBG_SPNIDEN 0x00000008
#define PROC_BOOT_CFG_FLAG_ARMV8_AARCH32 0x00000100
/* R5 Config Flags */
#define PROC_BOOT_CFG_FLAG_R5_DBG_EN 0x00000001
#define PROC_BOOT_CFG_FLAG_R5_DBG_NIDEN 0x00000002
#define PROC_BOOT_CFG_FLAG_R5_LOCKSTEP 0x00000100
#define PROC_BOOT_CFG_FLAG_R5_TEINIT 0x00000200
#define PROC_BOOT_CFG_FLAG_R5_NMFI_EN 0x00000400
#define PROC_BOOT_CFG_FLAG_R5_TCM_RSTBASE 0x00000800
#define PROC_BOOT_CFG_FLAG_R5_BTCM_EN 0x00001000
#define PROC_BOOT_CFG_FLAG_R5_ATCM_EN 0x00002000
/**
* struct ti_sci_msg_req_set_proc_boot_config - Set Processor boot configuration
* @hdr: Generic Header
* @processor_id: ID of processor
* @bootvector_low: Lower 32bit (Little Endian) of boot vector
* @bootvector_high: Higher 32bit (Little Endian) of boot vector
* @config_flags_set: Optional Processor specific Config Flags to set.
* Setting a bit here implies required bit sets to 1.
* @config_flags_clear: Optional Processor specific Config Flags to clear.
* Setting a bit here implies required bit gets cleared.
*
* Request type is TISCI_MSG_SET_PROC_BOOT_CONFIG, response is a generic
* ACK/NACK message.
*/
struct
ti_sci_msg_req_set_proc_boot_config
{
struct
ti_sci_msg_hdr
hdr
;
uint8_t
processor_id
;
uint32_t
bootvector_low
;
uint32_t
bootvector_high
;
uint32_t
config_flags_set
;
uint32_t
config_flags_clear
;
}
__packed
;
/* R5 Control Flags */
#define PROC_BOOT_CTRL_FLAG_R5_CORE_HALT 0x00000001
/**
* struct ti_sci_msg_req_set_proc_boot_ctrl - Set Processor boot control flags
* @hdr: Generic Header
* @processor_id: ID of processor
* @config_flags_set: Optional Processor specific Config Flags to set.
* Setting a bit here implies required bit sets to 1.
* @config_flags_clear: Optional Processor specific Config Flags to clear.
* Setting a bit here implies required bit gets cleared.
*
* Request type is TISCI_MSG_SET_PROC_BOOT_CTRL, response is a generic ACK/NACK
* message.
*/
struct
ti_sci_msg_req_set_proc_boot_ctrl
{
struct
ti_sci_msg_hdr
hdr
;
uint8_t
processor_id
;
uint32_t
control_flags_set
;
uint32_t
control_flags_clear
;
}
__packed
;
/**
* struct ti_sci_msg_req_proc_auth_start_image - Authenticate and start image
* @hdr: Generic Header
* @processor_id: ID of processor
* @cert_addr_low: Lower 32bit (Little Endian) of certificate
* @cert_addr_high: Higher 32bit (Little Endian) of certificate
*
* Request type is TISCI_MSG_PROC_AUTH_BOOT_IMAGE, response is a generic
* ACK/NACK message.
*/
struct
ti_sci_msg_req_proc_auth_boot_image
{
struct
ti_sci_msg_hdr
hdr
;
uint8_t
processor_id
;
uint32_t
cert_addr_low
;
uint32_t
cert_addr_high
;
}
__packed
;
/**
* struct ti_sci_msg_req_get_proc_boot_status - Get processor boot status
* @hdr: Generic Header
* @processor_id: ID of processor
*
* Request type is TISCI_MSG_GET_PROC_BOOT_STATUS, response is appropriate
* message, or NACK in case of inability to satisfy request.
*/
struct
ti_sci_msg_req_get_proc_boot_status
{
struct
ti_sci_msg_hdr
hdr
;
uint8_t
processor_id
;
}
__packed
;
/* ARMv8 Status Flags */
#define PROC_BOOT_STATUS_FLAG_ARMV8_WFE 0x00000001
#define PROC_BOOT_STATUS_FLAG_ARMV8_WFI 0x00000002
/* R5 Status Flags */
#define PROC_BOOT_STATUS_FLAG_R5_WFE 0x00000001
#define PROC_BOOT_STATUS_FLAG_R5_WFI 0x00000002
#define PROC_BOOT_STATUS_FLAG_R5_CLK_GATED 0x00000004
#define PROC_BOOT_STATUS_FLAG_R5_LOCKSTEP_PERMITTED 0x00000100
/**
* \brief Processor Status Response
* struct ti_sci_msg_resp_get_proc_boot_status - Processor boot status response
* @hdr: Generic Header
* @processor_id: ID of processor
* @bootvector_low: Lower 32bit (Little Endian) of boot vector
* @bootvector_high: Higher 32bit (Little Endian) of boot vector
* @config_flags: Optional Processor specific Config Flags set.
* @control_flags: Optional Processor specific Control Flags.
* @status_flags: Optional Processor specific Status Flags set.
*
* Response to TISCI_MSG_GET_PROC_BOOT_STATUS.
*/
struct
ti_sci_msg_resp_get_proc_boot_status
{
struct
ti_sci_msg_hdr
hdr
;
uint8_t
processor_id
;
uint32_t
bootvector_low
;
uint32_t
bootvector_high
;
uint32_t
config_flags
;
uint32_t
control_flags
;
uint32_t
status_flags
;
}
__packed
;
#endif
/* __TI_SCI_PROTOCOL_H */
plat/ti/k3/common/k3_bl31_setup.c
View file @
a542faad
...
...
@@ -14,6 +14,7 @@
#include <platform_def.h>
#include <k3_gicv3.h>
#include <string.h>
#include <ti_sci.h>
/* Table of regions to map using the MMU */
const
mmap_region_t
plat_arm_mmap
[]
=
{
...
...
@@ -21,6 +22,9 @@ const mmap_region_t plat_arm_mmap[] = {
MAP_REGION_FLAT
(
K3_USART_BASE_ADDRESS
,
K3_USART_SIZE
,
MT_DEVICE
|
MT_RW
|
MT_SECURE
),
MAP_REGION_FLAT
(
K3_GICD_BASE
,
K3_GICD_SIZE
,
MT_DEVICE
|
MT_RW
|
MT_SECURE
),
MAP_REGION_FLAT
(
K3_GICR_BASE
,
K3_GICR_SIZE
,
MT_DEVICE
|
MT_RW
|
MT_SECURE
),
MAP_REGION_FLAT
(
SEC_PROXY_RT_BASE
,
SEC_PROXY_RT_SIZE
,
MT_DEVICE
|
MT_RW
|
MT_SECURE
),
MAP_REGION_FLAT
(
SEC_PROXY_SCFG_BASE
,
SEC_PROXY_SCFG_SIZE
,
MT_DEVICE
|
MT_RW
|
MT_SECURE
),
MAP_REGION_FLAT
(
SEC_PROXY_DATA_BASE
,
SEC_PROXY_DATA_SIZE
,
MT_DEVICE
|
MT_RW
|
MT_SECURE
),
{
/* sentinel */
}
};
...
...
@@ -118,6 +122,8 @@ void bl31_platform_setup(void)
{
k3_gic_driver_init
(
K3_GICD_BASE
,
K3_GICR_BASE
);
k3_gic_init
();
ti_sci_init
();
}
void
platform_mem_init
(
void
)
...
...
plat/ti/k3/common/k3_psci.c
View file @
a542faad
...
...
@@ -9,8 +9,11 @@
#include <debug.h>
#include <k3_gicv3.h>
#include <psci.h>
#include <platform.h>
#include <stdbool.h>
#include <ti_sci.h>
#define STUB() ERROR("stub %s called\n", __func__)
uintptr_t
k3_sec_entrypoint
;
...
...
@@ -33,9 +36,40 @@ static void k3_cpu_standby(plat_local_state_t cpu_state)
static
int
k3_pwr_domain_on
(
u_register_t
mpidr
)
{
sev
();
/* TODO: Indicate to System firmware about powering up */
int
core_id
,
proc
,
device
,
ret
;
core_id
=
plat_core_pos_by_mpidr
(
mpidr
);
if
(
core_id
<
0
)
{
ERROR
(
"Could not get target core id: %d
\n
"
,
core_id
);
return
PSCI_E_INTERN_FAIL
;
}
proc
=
PLAT_PROC_START_ID
+
core_id
;
device
=
PLAT_PROC_DEVICE_START_ID
+
core_id
;
ret
=
ti_sci_proc_request
(
proc
);
if
(
ret
)
{
ERROR
(
"Request for processor failed: %d
\n
"
,
ret
);
return
PSCI_E_INTERN_FAIL
;
}
ret
=
ti_sci_proc_set_boot_cfg
(
proc
,
k3_sec_entrypoint
,
0
,
0
);
if
(
ret
)
{
ERROR
(
"Request to set core boot address failed: %d
\n
"
,
ret
);
return
PSCI_E_INTERN_FAIL
;
}
ret
=
ti_sci_device_get
(
device
);
if
(
ret
)
{
ERROR
(
"Request to start core failed: %d
\n
"
,
ret
);
return
PSCI_E_INTERN_FAIL
;
}
ret
=
ti_sci_proc_release
(
proc
);
if
(
ret
)
{
/* this is not fatal */
WARN
(
"Could not release processor control: %d
\n
"
,
ret
);
}
return
PSCI_E_SUCCESS
;
}
...
...
@@ -58,8 +92,8 @@ void k3_pwr_domain_on_finish(const psci_power_state_t *target_state)
static
void
__dead2
k3_system_reset
(
void
)
{
/*
TODO: Indicate to System firmware about system reset
*/
STUB
();
/*
Send the system reset request to system firmware
*/
ti_sci_core_reboot
();
while
(
true
)
wfi
();
...
...
plat/ti/k3/common/plat_common.mk
View file @
a542faad
...
...
@@ -36,6 +36,8 @@ PLAT_INCLUDES += \
-I
${PLAT_PATH}
/include
\
-Iinclude
/plat/arm/common/
\
-Iinclude
/plat/arm/common/aarch64/
\
-I
${PLAT_PATH}
/common/drivers/sec_proxy
\
-I
${PLAT_PATH}
/common/drivers/ti_sci
\
K3_CONSOLE_SOURCES
+=
\
drivers/console/aarch64/console.S
\
...
...
@@ -53,6 +55,12 @@ K3_PSCI_SOURCES += \
plat/common/plat_psci_common.c
\
${PLAT_PATH}
/common/k3_psci.c
\
K3_SEC_PROXY_SOURCES
+=
\
${PLAT_PATH}
/common/drivers/sec_proxy/sec_proxy.c
\
K3_TI_SCI_SOURCES
+=
\
${PLAT_PATH}
/common/drivers/ti_sci/ti_sci.c
\
PLAT_BL_COMMON_SOURCES
+=
\
plat/arm/common/arm_common.c
\
lib/cpus/aarch64/cortex_a53.S
\
...
...
@@ -65,3 +73,5 @@ BL31_SOURCES += \
${PLAT_PATH}
/common/k3_topology.c
\
${K3_GIC_SOURCES}
\
${K3_PSCI_SOURCES}
\
${K3_SEC_PROXY_SOURCES}
\
${K3_TI_SCI_SOURCES}
\
plat/ti/k3/include/platform_def.h
View file @
a542faad
...
...
@@ -106,7 +106,7 @@
* runtime memory used, choose the smallest value needed to register the
* required regions for each BL stage.
*/
#define MAX_MMAP_REGIONS
8
#define MAX_MMAP_REGIONS
11
/*
* Defines the total size of the address space in bytes. For example, for a 32
...
...
@@ -193,4 +193,17 @@
#define K3_GICR_BASE 0x01880000
#define K3_GICR_SIZE 0x100000
#define SEC_PROXY_DATA_BASE 0x32C00000
#define SEC_PROXY_DATA_SIZE 0x80000
#define SEC_PROXY_SCFG_BASE 0x32800000
#define SEC_PROXY_SCFG_SIZE 0x80000
#define SEC_PROXY_RT_BASE 0x32400000
#define SEC_PROXY_RT_SIZE 0x80000
#define SEC_PROXY_TIMEOUT_US 1000000
#define SEC_PROXY_MAX_MESSAGE_SIZE 56
#define TI_SCI_HOST_ID 10
#define TI_SCI_MAX_MESSAGE_SIZE 52
#endif
/* __PLATFORM_DEF_H__ */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment